<?php

class Xcrud
{
    protected static $_instance = array();
    protected $_instance_name = 'xcrud';
    protected $instance_count;
    protected $table;
    protected $table_name;
    protected $primary;
    protected $primary_key;
    protected $where = array();
    protected $order_by = array();
    protected $join = array();
    protected $fields = array();
    protected $fields_names = array();
    protected $labels = array();
    protected $columns = array();
    protected $columns_names = array();
    protected $is_add = true;
    protected $is_edit = true;
    protected $is_remove = true;
    protected $is_csv = true;
    protected $is_search = true;
    protected $is_print = true;
    protected $buttons = array();
    protected $readonly = array();
    protected $disabled = array();
    protected $readonly_on_create = array();
    protected $disabled_on_create = array();
    protected $readonly_on_edit = array();
    protected $disabled_on_edit = array();
    protected $validation_required = array();
    protected $validation_pattern = array();
    protected $before_insert = array();
    protected $before_update = array();
    protected $before_remove = array();
    protected $before_view = array();
    protected $after_insert = array();
    protected $after_update = array();
    protected $after_remove = array();
    protected $field_type = array();
    protected $field_maxsize = array();
    protected $defaults = array();
    protected $limit = 20;
    protected $limit_list = array(
        '20',
        '50',
        '100',
        'all');
    protected $column_cut = 50;
    protected $no_editor = array();
    protected $show_primary_ai_field = false;
    protected $show_primary_ai_column = false;
    protected $disable_jquery = false;
    protected $disable_jquery_ui = false;
    protected $disable_plugins = false;
    protected $crud_url;
    protected $url;
    protected $self_path;
    protected $is_ajax_request;
    protected $key;
    protected $jquery_no_conflict = false;
    protected $sess_expire = 30;
    protected $tinymce_folder_url = '';
    protected $tinymce_init_url = '';
    protected $force_tinymce = false;
    protected $benchmark = false;
    protected $search_pattern = array('%', '%');
    protected $connection = false;
    protected $start_minimized = false;
    protected $remove_confirm = false;
    //v.1.1
    protected $upload_folder = array();
    protected $upload_config = array();
    protected $upload_folder_def = '../uploads';
    protected $upload_to_save = array();
    protected $upload_to_remove = array();
    protected $binary = array();
    // v.1.2
    protected $pass_var_create = array();
    protected $pass_var_edit = array();
    // v.1.3
    protected $reverse_columns = false;
    protected $reverse_fields = false;
    // v.1.4
    protected $no_quotes = array();
    protected $table_join = array();
    protected $inner_where = array();
    protected $inner_table_instance = array();
    protected $condition = array();
    protected $theme = 'default';
    protected $unique = array();
    protected $fk_join = array();
    protected $is_duplicate = false;
    protected $links_label = array();
    protected $emails_label = array();
    protected $sum = array();
    protected $alert_create;
    protected $alert_edit;


    protected function __construct()
    {
        $this->self_path = dirname(__file__);
        require_once ($this->self_path . '/xcrud_config.php');
        require_once ($this->self_path . '/xcrud_db.php');
        $this->is_ajax_request = (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) ==
            'xmlhttprequest') ? true : false;
        $this->crud_url = $this->_check_url(Xcrud_config::$scripts_url);
        $this->limit = Xcrud_config::$limit;
        $this->limit_list = Xcrud_config::$limit_list;
        $this->column_cut = Xcrud_config::$column_cut;
        $this->show_primary_ai_field = Xcrud_config::$show_primary_ai_field;
        $this->show_primary_ai_column = Xcrud_config::$show_primary_ai_column;
        $this->disable_plugins = Xcrud_config::$disable_plugins;
        $this->disable_jquery = Xcrud_config::$disable_jquery;
        $this->disable_jquery_ui = Xcrud_config::$disable_jquery_ui;
        $this->jquery_no_conflict = Xcrud_config::$jquery_no_conflict;
        $this->sess_expire = Xcrud_config::$sess_expire;
        $this->sess_name = Xcrud_config::$sess_name;
        $this->tinymce_folder_url = $this->_check_url(Xcrud_config::$tinymce_folder_url);
        $this->tinymce_init_url = $this->_check_url(Xcrud_config::$tinymce_init_url);
        $this->force_tinymce = Xcrud_config::$force_tinymce;
        $this->benchmark = Xcrud_config::$benchmark;
        $this->start_minimized = Xcrud_config::$start_minimized;
        $this->remove_confirm = Xcrud_config::$remove_confirm;
        $this->upload_folder_def = Xcrud_config::$upload_folder_def;
        $this->theme = Xcrud_config::$theme;
        $this->is_print = Xcrud_config::$enable_printout;
        if (!session_id())
        {
            if (!headers_sent())
            {
                if (Xcrud_config::$dynamic_session && ($this->_post('sess_name') or $this->_get('sess_name')))
                {
                    $this->sess_name = $this->_post('sess_name') ? $this->_post('sess_name') : $this->_get('sess_name');
                }
                session_name($this->sess_name);
                session_cache_expire($this->sess_expire);
                session_start();
            } else
                $this->error('xCRUD can not create session, because the output is already sent into browser. Try to define xCRUD instance before the output start or use session_start() at the beginning of your script');
        } elseif (Xcrud_config::$dynamic_session)
        {
            $this->sess_name = session_name();
        }
    }
    protected function __clone()
    {
    }
    public static function get_instance($name = 'xcrud')
    {
        if (!isset(self::$_instance[$name]) || null === self::$_instance[$name])
        {
            self::$_instance[$name] = new self();
            self::$_instance[$name]->_instance_name = $name;
        }
        self::$_instance[$name]->instance_count = count(self::$_instance);
        return self::$_instance[$name];
    }
    public function connection($user = '', $pass = '', $table = '', $host = 'localhost', $encode = 'utf8')
    {
        if ($user && $pass && $table)
        {
            $this->connection = array(
                $user,
                $pass,
                $table,
                $host,
                $encode);
        }
        return $this;
    }
    public function start_minimized($bool = true)
    {
        $this->start_minimized = (bool)$bool;
        return $this;
    }
    public function remove_confirm($bool = true)
    {
        $this->remove_confirm = (bool)$bool;
        return $this;
    }
    public function disable_jquery($bool = true)
    {
        $this->disable_jquery = (bool)$bool;
        return $this;
    }
    public function disable_jquery_ui($bool = true)
    {
        $this->disable_jquery_ui = (bool)$bool;
        return $this;
    }
    public function scripts_url($url)
    {
        $this->crud_url = $this->_check_url($url);
        return $this;
    }
    public function jquery_no_conflict($bool = true)
    {
        $this->jquery_no_conflict = (bool)$bool;
        return $this;
    }
    public function theme($theme = 'default')
    {
        $this->theme = $theme;
    }
    public function limit($limit = 20)
    {
        $this->limit = $limit;
        return $this;
    }
    public function limit_list($limit_list = array(
        '20',
        '50',
        '100',
        'all'))
    {
        if ($limit_list)
        {
            if (is_array($limit_list))
                $this->limit_list = array_unique($limit_list);
            else
            {
                $this->limit_list = array_unique(explode(',', str_replace(' ', '', $limit_list)));
            }
        }
        return $this;
    }
    public function sess_expire($minutes = 30)
    {
        if ((int)$minutes)
            $this->sess_expire = (int)$minutes;
        return $this;
    }
    public function show_primary_ai_field($bool = true)
    {
        $this->show_primary_ai_field = (bool)$bool;
        return $this;
    }
    public function show_primary_ai_column($bool = true)
    {
        $this->show_primary_ai_column = (bool)$bool;
        return $this;
    }
    public function tinymce_folder_url($url = '')
    {
        $this->tinymce_folder_url = $this->_check_url($url);
        $this->force_tinymce = true;
        return $this;
    }
    public function tinymce_init_url($url = '')
    {
        $this->tinymce_init_url = $this->_check_url($url);
        $this->force_tinymce = false;
        return $this;
    }
    public function force_tinymce($bool = true)
    {
        $this->force_tinymce = (bool)$bool;
        return $this;
    }
    public function table($table = '')
    {
        $this->table = $table;
        return $this;
    }
    public function table_name($name = '')
    {
        if ($name)
            $this->table_name = $name;
        return $this;
    }
    public function where($where_field = '', $where_val = '')
    {
        if ($where_field)
        {
            if (is_array($where_field))
            {
                $this->where = array_merge($this->where, $where_field);
            } else
            {
                $this->where[$where_field] = $where_val;
            }
        }
        return $this;
    }
    public function order_by($field = '', $direction = 'asc')
    {
        if ($field)
        {
            if (is_array($field))
            {
                $this->order_by = array_merge($this->order_by, $field);
            } else
                $this->order_by[$field] = $direction;
        }
        return $this;
    }
    public function relation($field = '', $rel_tbl = '', $rel_field = '', $rel_name = '', $rel_where = array(), $multi = false,
        $rel_concat_separator = '-')
    {
        $this->join[$field] = array(
            'rel_tbl' => $rel_tbl,
            'rel_alias' => 'alias' . rand(111, 999),
            'rel_field' => $rel_field,
            'rel_name' => $rel_name,
            'rel_where' => $rel_where,
            'rel_separator' => $rel_concat_separator,
            'multi' => $multi);
        return $this;
    }
    public function fk_relation($field = '', $rel_tbl = '', $rel_field = '', $rel_name = '', $rel_where = array(), $fk_table =
        '', $in_fk_fiend = '', $out_fk_field = '')
    {
        $this->fk_join[] = array(
            'field' => $field,
            'rel_tbl' => $rel_tbl,
            'rel_alias' => 'alias' . rand(111, 999),
            'fk_alias' => 'alias' . rand(111, 999),
            'rel_field' => $rel_field,
            'rel_name' => $rel_name,
            'rel_where' => $rel_where,
            'fk_table' => $fk_table,
            'in_fk_fiend,' => $in_fk_fiend,
            'out_fk_field' => $out_fk_field);
        return $this;
    }
    public function join($field = '', $join_tbl = '', $join_field = '')
    {
        $table_join[$join_tbl] = array('field' => $field, 'join_field' => $join_field /*,
                'alias' => 'alias' . rand(111, 999) . 't'*/);
        return $this;
    }
    public function nested_table($instance_var = '', $field = '', $inner_tbl = '', $tbl_field = '')
    {
        if ($instance_var)
        {
            $this->$instance_var = Xcrud::get_instance($this->instance_name() . '_inner_' . $field);
            $this->$instance_var->table($inner_tbl);
            $this->inner_table_instance[$field] = $this->$instance_var;
            $this->inner_where[$field] = $tbl_field;
            return $this->$instance_var;
        }
    }
    public function primary($key = '')
    {
        if ($key)
        {
            $this->primary = $key;
        }
        return $this;
    }
    public function fields($fields = '', $reverse = false)
    {
        if ($fields)
        {
            if (is_array($fields))
                $this->fields = array_unique(array_merge($this->fields, $fields));
            else
            {
                $this->fields = array_unique(array_merge($this->fields, explode(',', str_replace(' ', '', $fields))));
            }
            $this->reverse_fields = $reverse;
        }
        return $this;
    }
    public function unique($fields = '')
    {
        if ($fields)
        {
            if (is_array($fields))
            {
                foreach ($fields as $field)
                {
                    $this->unique[$field] = true;
                }
            } else
            {
                $fields = explode(',', str_replace(' ', '', $fields));
                foreach ($fields as $field)
                {
                    $this->unique[$field] = true;
                }
            }
        }
        return $this;
    }
    public function label($field = '', $label = '')
    {
        if ($field && is_array($field))
        {
            $this->labels = array_merge($this->labels, $field);
        } else
            if ($field && $label)
            {
                $this->labels[$field] = $label;
            }
        return $this;
    }
    public function columns($columns = '', $reverse = false)
    {
        if ($columns)
        {
            if (is_array($columns))
                $this->columns = array_unique(array_merge($this->columns, $columns));
            else
                $this->columns = array_unique(array_merge($this->columns, explode(',', str_replace(' ', '', $columns))));
            $this->reverse_columns = $reverse;
        }
        return $this;
    }
    public function unset_add($bool = true)
    {
        $this->is_add = !(bool)$bool;
        return $this;
    }
    public function unset_edit($bool = true)
    {
        $this->is_edit = !(bool)$bool;
        return $this;
    }
    public function unset_remove($bool = true)
    {
        $this->is_remove = !(bool)$bool;
        return $this;
    }
    public function unset_csv($bool = true)
    {
        $this->is_csv = !(bool)$bool;
        return $this;
    }
    public function duplicate_button($bool = true)
    {
        $this->is_duplicate = (bool)$bool;
        return $this;
    }
    public function unset_search($bool = true)
    {
        $this->is_search = !(bool)$bool;
        return $this;
    }
    public function unset_print($bool = true)
    {
        $this->is_print = !(bool)$bool;
        return $this;
    }

    public function button($link = '', $name = '', $icon = '', $class = '', $parameter_name = '', $parameter_field = '')
    {
        if ($link)
        {
            if (!is_array($parameter_name) && $parameter_name)
            {
                $parameter_name = array($parameter_name => $parameter_field);
            }
            $this->buttons[] = array(
                'link' => $link,
                'name' => $name,
                'icon' => $icon,
                'class' => $class,
                'params' => $parameter_name);
        }
        return $this;
    }
    public function change_type($field = '', $type = '', $default = '', $max = '')
    {
        if ($field && $type)
        {
            switch ($type)
            {
                case 'file':
                case 'image':
                    $this->defaults[$field] = '';
                    if ($default)
                        $this->upload_folder[$field] = rtrim($default, '/');
                    if ($max)
                        $this->upload_config[$field] = $max;
                    break;
                case 'price':
                    $this->field_maxsize[$field] = array(
                        'max' => (isset($max['max']) ? $max['max'] : 10),
                        'decimals' => (isset($max['decimals']) ? $max['decimals'] : 2),
                        'separator' => (isset($max['separator']) ? $max['separator'] : ','),
                        'prefix' => (isset($max['prefix']) ? $max['prefix'] : ''),
                        'suffix' => (isset($max['suffix']) ? $max['suffix'] : ''));
                    $this->defaults[$field] = $default;
                    break;
                default:
                    $this->defaults[$field] = $default;
                    $this->field_maxsize[$field] = $max;
                    break;
            }
            $this->field_type[$field] = $type;
        }
        return $this;
    }
    public function pass_default($field = '', $value = '')
    {
        if ($field && is_array($field))
        {
            $this->defaults = array_merge($this->defaults, $field);
        } else
            if ($field && $value)
            {
                $this->defaults[$field] = $value;
            }
        return $this;
    }
    public function pass_var($field = '', $var = '', $type = 'all')
    {
        if ($field)
        {
            if ($type != 'edit')
                $this->pass_var_create[$field] = $var;
            if ($type != 'create')
                $this->pass_var_edit[$field] = $var;
        }
        return $this;
    }
    public function no_quotes($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->no_quotes[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->no_quotes[$field] = true;
                }
            }
        }
        return $this;
    }
    public function sum($name = '', $table = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->sum[$field] = $table;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->sum[$field] = $table;
                }
            }
        }
        return $this;
    }
    public function readonly_on_create($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->readonly_on_create[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->readonly_on_create[$field] = true;
                }
            }
        }
        return $this;
    }
    public function disabled_on_create($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->disabled_on_create[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->disabled_on_create[$field] = true;
                }
            }
        }
        return $this;
    }
    public function readonly_on_edit($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->readonly_on_edit[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->readonly_on_edit[$field] = true;
                }
            }
        }
        return $this;
    }
    public function disabled_on_edit($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->disabled_on_edit[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->disabled_on_edit[$field] = true;
                }
            }
        }
        return $this;
    }
    public function readonly($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->readonly_on_create[$field] = true;
                    $this->readonly_on_edit[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->readonly_on_create[$field] = true;
                    $this->readonly_on_edit[$field] = true;
                }
            }
        }
        return $this;
    }
    public function disabled($name = '')
    {
        if ($name)
        {
            if (is_array($name))
            {
                foreach ($name as $field)
                {
                    $this->disabled_on_create[$field] = true;
                    $this->disabled_on_edit[$field] = true;
                }
            } else
            {
                $name = explode(',', str_replace(' ', '', $name));
                foreach ($name as $field)
                {
                    $this->disabled_on_create[$field] = true;
                    $this->disabled_on_edit[$field] = true;
                }
            }
        }
        return $this;
    }
    public function condition($field = '', $operator = '', $value = '', $method = '', $param = '')
    {
        if ($field && $method && $operator)
        {
            $this->condition[$field] = array(
                'value' => $value,
                'operator' => $operator,
                'method' => $method,
                'param' => $param);
        }
        return $this;
    }
    public function instance_name()
    {
        return $this->_instance_name;
    }
    public function benchmark($bool = true)
    {
        $this->benchmark = (bool)$bool;
        return $this;
    }
    public function column_cut($int = 50)
    {
        $this->column_cut = (int)$int ? (int)$int : 50;
        return $this;
    }
    public function links_label($text = '')
    {
        if ($text)
        {
            $this->links_label['text'] = trim($text);
        }
        return $this;
    }
    public function emails_label($text = '')
    {
        if ($text)
        {
            $this->emails_label['text'] = trim($text);
        }
        return $this;
    }

    public function no_editor($fields)
    {
        if (is_array($fields))
        {
            foreach ($fields as $field)
            {
                $this->no_editor[$field] = true;
            }
        } else
        {
            $editor = explode(',', str_replace(' ', '', $fields));
            foreach ($editor as $field)
            {
                $this->no_editor[$field] = true;
            }
        }
        return $this;
    }
    public function validation_required($field = '', $chars = 1)
    {
        if ($field)
        {
            if (is_array($field))
            {
                $this->validation_required = array_merge($this->validation_required, $field);
            } else
                $this->validation_required[$field] = $chars;
        }
        return $this;
    }
    public function validation_pattern($field = '', $pattern = '')
    {
        if ($field)
        {
            if (is_array($field))
            {
                $this->validation_pattern = array_merge($this->validation_pattern, $field);
            } else
                if ($pattern)
                    $this->validation_pattern[$field] = $pattern;
        }
        return $this;
    }
    public function alert($column = '', $cc = '', $subject = '', $message = '', $link = false, $field = false, $value = false)
    {
        if ($cc)
        {
            if (!is_array($fields))
                $cc = explode(',', str_replace(' ', '', $cc));
        }
        $this->alert_create[] = array(
            'column' => $column,
            'cc' => $cc,
            'subject' => $subject,
            'message' => $message,
            'link' => $link,
            'field' => $field,
            'value' => $value);
        $this->alert_edit[] = array(
            'column' => $column,
            'cc' => $cc,
            'subject' => $subject,
            'message' => $message,
            'link' => $link,
            'field' => $field,
            'value' => $value);
        return $this;
    }
    public function alert_create($column = '', $cc = '', $subject = '', $message = '', $link = false, $field = false, $value = false)
    {
        if ($cc)
        {
            if (!is_array($fields))
                $cc = explode(',', str_replace(' ', '', $cc));
        }
        $this->alert_create[] = array(
            'column' => $column,
            'cc' => $cc,
            'subject' => $subject,
            'message' => $message,
            'link' => $link,
            'field' => $field,
            'value' => $value);
        return $this;
    }
    public function alert_edit($column = '', $cc = '', $subject = '', $message = '', $link = false, $field = false, $value = false)
    {
        if ($cc)
        {
            if (!is_array($fields))
                $cc = explode(',', str_replace(' ', '', $cc));
        }
        $this->alert_edit[] = array(
            'column' => $column,
            'cc' => $cc,
            'subject' => $subject,
            'message' => $message,
            'link' => $link,
            'field' => $field,
            'value' => $value);
        return $this;
    }

    public function before_insert($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->before_insert['class'] = $class ? $class : '';
            $this->before_insert['func'] = $func;
            $this->before_insert['lib'] = $lib;
            $this->before_insert['act'] = $parent_act;
        }
        return $this;
    }
    public function before_update($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->before_update['class'] = $class ? $class : '';
            $this->before_update['func'] = $func;
            $this->before_update['lib'] = $lib;
            $this->before_update['act'] = $parent_act;
        }
        return $this;
    }
    public function before_remove($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->before_remove['class'] = $class ? $class : '';
            $this->before_remove['func'] = $func;
            $this->before_remove['lib'] = $lib;
            $this->before_remove['act'] = $parent_act;
        }
        return $this;
    }
    public function after_insert($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->after_insert['class'] = $class ? $class : '';
            $this->after_insert['func'] = $func;
            $this->after_insert['lib'] = $lib;
            $this->after_insert['act'] = $parent_act;
        }
        return $this;
    }
    public function after_update($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->after_update['class'] = $class ? $class : '';
            $this->after_update['func'] = $func;
            $this->after_update['lib'] = $lib;
            $this->after_update['act'] = $parent_act;
        }
        return $this;
    }
    public function after_remove($class = '', $func = '', $lib = '', $parent_act = '')
    {
        if ($func && $lib)
        {
            $this->after_remove['class'] = $class ? $class : '';
            $this->after_remove['func'] = $func;
            $this->after_remove['lib'] = $lib;
            $this->after_remove['act'] = $parent_act;
        }
        return $this;
    }
    public function _image_check()
    {
        $instanse_name = $this->instance_name();
        if (!isset($_SESSION['xcrud_' . $instanse_name]['key']) || $this->_get('key') != $_SESSION['xcrud_' . $instanse_name]['key'])
            $this->error('Your session has gone... Please, reload the page');
        else
            $this->_import_vars($instanse_name);
    }
    public function _ajax_check()
    {
        $instanse_name = $this->instance_name();
        if (!isset($_SESSION['xcrud_' . $instanse_name]['key']) || $this->_post('key') != $_SESSION['xcrud_' . $instanse_name]['key'])
            $this->error('Your session has gone... Please, reload the page');
        else
            $this->_import_vars($instanse_name);
    }
    public function render()
    {
        $this->benchmark_start();
        $this->_receive_post();
        $this->key = $this->_regenerate_key();
        if (!$this->table_name)
            $this->table_name = $this->_humanize($this->table);
        $this->_remove_and_save_uploads();
        $this->_export_vars();
        $this->_export_inner_vars();
        switch ($this->_post('task'))
        {
            case 'create':
                $this->_set_field_types($this->_table_info());
                $this->_sort_defaults();
                return $this->_create();
                break;
            case 'edit':
                $this->_set_field_types($this->_table_info());
                return $this->_edit($this->_post('primary'));
                break;
            case 'save':
                $table_info = $this->_table_info();
                $primary = $this->_save();
                switch ($this->_post('after'))
                {
                    case 'create':
                        $this->_set_field_types($table_info);
                        $this->_sort_defaults();
                        return $this->_create();
                        break;
                    case 'edit':
                        $this->_set_field_types($table_info);
                        return $this->_edit($primary);
                        break;
                    case 'list':
                    default:
                        $this->_set_columns($table_info);
                        return $this->_list();
                        break;
                }
                break;
            case 'remove':
                $this->_set_columns($this->_table_info());
                $this->_remove($this->_post('primary'));
                return $this->_list();
                break;
            case 'upload':
                return $this->_upload();
                break;
            case 'remove_upload':
                return $this->_remove_upload();
                break;
            case 'unique':
                return $this->_check_unique_value();
                break;
            case 'clone':
                $this->_set_columns($this->_table_info(), true);
                $this->_clone_row($this->_post('primary'));
                return $this->_list();
                break;
            case 'print':
                $this->_set_columns($this->_table_info());
                $this->theme = 'printout';
                return $this->_list();
            case 'list':
            default:
                $this->_set_columns($this->_table_info());
                return $this->_list();
                break;
        }
    }
    public function render_inner()
    {
        $this->benchmark_start();
        //$this->instance_count = count(self::$_instance);
        $this->key = $this->_regenerate_key();
        if (!$this->table_name)
            $this->table_name = $this->_humanize($this->table);
        $this->_remove_and_save_uploads();
        $this->_export_vars();
        $this->_export_inner_vars();
        $this->_set_columns($this->_table_info());
        return $this->_list();
    }
    public function render_image()
    {
        $field = $this->_get('field');
        if (!$field)
            exit();
        if ($this->_get('primary_key'))
            $this->primary_key = $this->_get('primary_key');
        $thumb = $this->_get('thumb') ? true : false;
        $marker = (isset($this->upload_config[$field]['thumb_marker']) && $this->upload_config[$field]['thumb_marker']) ? $this->
            upload_config[$field]['thumb_marker'] : '_thumb';
        $image = array_search($field, array_reverse($this->upload_to_save));
        if (!$image)
        {
            $db = Xcrud_db::get_instance($this->connection);
            $db->query("SELECT `{$field}` FROM `{$this->table}` WHERE `{$this->primary}` = " . $db->escape($this->primary_key) .
                " LIMIT 1");
            $image = $db->row()->$field;
            if (isset($this->upload_config[$field]['blob']) && $this->upload_config[$field]['blob'] === true)
            {
                $output = $image;
                unset($image);
            } else
            {
                $folder = isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def;
                $image = ($thumb ? substr_replace($image, $marker, strrpos($image, '.'), 0) : $image);
                $path = realpath($folder) . '/' . $image;
                if (!file_exists($path))
                {
                    header("HTTP/1.0 404 Not Found");
                    exit('Not Found');
                }
                $output = file_get_contents($path);
            }
        } else
        {
            $folder = isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def;
            $image = ($thumb ? substr_replace($image, $marker, strrpos($image, '.'), 0) : $image);
            $path = realpath($folder) . '/' . $image;
            if (!file_exists($path))
            {
                header("HTTP/1.0 404 Not Found");
                exit('Not Found');
            }
            $output = file_get_contents($path);
        }

        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: public");
        if ($this->field_type[$field] == 'image')
        {
            header("Content-type: image/*");
        } else
        {
            header("Content-type: application/octet-stream");
            header("Content-Disposition: attachment; filename=\"" . $image . "\"");
            header("Content-Transfer-Encoding: binary");
        }
        if (isset($this->upload_config[$field]['blob']) && $this->upload_config[$field]['blob'] === true)
            header("Content-Length: " . strlen($output));
        else
            header("Content-Length: " . filesize(realpath($folder) . '/' . $image));
        echo $output;
        exit();
    }
    public function render_csv()
    {
        $this->_receive_post();
        $db = Xcrud_db::get_instance($this->connection);
        if (Xcrud_config::$csv_all_fields)
        {
            $head = $db->csv_head($this->table);
            $db->query("SELECT * FROM `{$this->table}`");
        } else
        {
            $this->_set_columns($this->_table_info());
            $select = $this->_build_select_list(true);
            $join = $this->_build_join();
            $where = $this->_build_where();
            $order_by = $this->_build_order_by();
            $head = $this->columns;
            $db->query("SELECT {$select} FROM `{$this->table}` {$join} {$where} {$order_by}");
        }
        $db->return_csv($this->table, $head);
    }
    protected function _post($field = '')
    {
        if (isset($_POST[$field]))
        {
            if (!is_array($_POST[$field]))
                return trim($_POST[$field]);
            return $_POST[$field];
        } else
            return '';
    }
    protected function _get($field = '')
    {
        if (isset($_GET[$field]))
        {
            if (!is_array($_GET[$field]))
                return trim($_GET[$field]);
            return $_GET[$field];
        } else
            return '';
    }
    protected function _create()
    {
        if (!$this->is_add)
            return $this->error('Forbidden');
        $this->_set_field_names();
        $this->primary_key = 0;
        return $this->_render_details($this->defaults, 'create');
    }
    protected function _edit($primary = '')
    {
        if (!$this->is_edit)
            return $this->error('Forbidden');
        $this->_set_field_names();
        $this->where[$this->primary] = $primary;
        $select = $this->_build_select_details();
        $where = $this->_build_where(false);
        //$join = $this->_build_join();

        $db = Xcrud_db::get_instance($this->connection);
        $db->query("SELECT {$select} FROM `{$this->table}` {$where} LIMIT 1");
        $list = $db->row();
        if ($this->condition)
        {
            foreach ($this->condition as $field => $params)
            {
                if (isset($list->$field) && $this->_compare($list->$field, $params['operator'], $params['value']))
                {
                    $this->$params['method']($params['param']);
                }
            }
        }
        return $this->_render_details($list, 'edit');
    }
    protected function _insert($postdata)
    {
        $set = array();
        $db = Xcrud_db::get_instance($this->connection);
        foreach ($postdata as $key => $val)
        {
            if (isset($this->field_type[$key]) && $this->field_type[$key] == 'password')
            {
                if (trim($val) == '')
                    continue;
                else
                {
                    switch ($this->defaults[$key])
                    {
                        case 'md5':
                            $val = md5($val);
                            break;
                        case 'sha1':
                            $val = sha1($val);
                            break;
                    }
                }
            }
            if (isset($this->field_type[$key]) && $this->field_type[$key] == 'timestamp')
                $val = strtotime($val);
            if (is_array($val))
            {
                $set["`{$key}`"] = $db->escape(implode(',', $val));
            } else
                $set["`{$key}`"] = ((isset($this->no_quotes[$key]) && isset($this->pass_var_create[$key])) ? $db->escape($val, true) : $db->
                    escape($val));
        }
        unset($postdata);
        $keys = array_keys($set);
        $db->query("INSERT INTO `{$this->table}` (" . implode(',', $keys) . ") VALUES (" . implode(',', $set) . ")");
        unset($set, $keys);
        return $db->insert_id();
    }
    protected function _update($postdata, $primary)
    {
        $set = array();
        $db = Xcrud_db::get_instance($this->connection);
        foreach ($postdata as $key => $val)
        {
            if (isset($this->field_type[$key]) && $this->field_type[$key] == 'password')
            {
                if (trim($val) == '')
                    continue;
                else
                {
                    switch ($this->defaults[$key])
                    {
                        case 'md5':
                            $val = md5($val);
                            break;
                        case 'sha1':
                            $val = sha1($val);
                            break;
                    }
                }
            }
            if (isset($this->field_type[$key]) && $this->field_type[$key] == 'timestamp')
                $val = strtotime($val);
            if (is_array($val))
            {
                $set[] = "`{$key}` = " . $db->escape(implode(',', $val));
            } else
                $set[] = "`{$key}` = " . ((isset($this->no_quotes[$key]) && isset($this->pass_var_edit[$key])) ? $db->escape($val, true) :
                    $db->escape(trim($val)));
        }
        $res = $db->query("UPDATE `{$this->table}` SET " . implode(',', $set) . " WHERE `{$this->primary}` = " . $db->escape($primary) .
            " LIMIT 1");
        if (isset($postdata[$this->primary]) && $res)
            $primary = $postdata[$this->primary];
        unset($postdata, $set);
        return $primary;
    }
    protected function _remove($primary)
    {
        if (!$this->is_remove)
            return $this->error('Forbidden');
        if ($this->before_remove)
        {
            include_once (realpath($this->before_remove['lib']));
            $callable = $this->before_remove['class'] ? array($this->before_remove['class'], $this->before_remove['func']) : $this->
                before_remove['func'];
            if (is_callable($callable))
            {
                call_user_func_array($callable, array($primary));
            }
        }
        $db = Xcrud_db::get_instance($this->connection);
        $del = $db->query("DELETE FROM `{$this->table}` WHERE `{$this->primary}` = " . $db->escape($primary) . " LIMIT 1");
        if ($this->after_remove)
        {
            include_once (realpath($this->after_remove['lib']));
            $callable = $this->after_remove['class'] ? array($this->after_remove['class'], $this->after_remove['func']) : $this->
                after_remove['func'];
            if (is_callable($callable))
            {
                call_user_func_array($callable, array($primary));
            }
        }
        return $del;
    }
    protected function _save()
    {
        $primary = $this->_post('primary');
        $postdata = $this->_post('postdata');
        if ($this->upload_config)
        {
            foreach ($this->upload_config as $key => $opts)
            {
                if (isset($opts['blob']) && $opts['blob'] && isset($postdata[$key]) && $postdata[$key] != '')
                {
                    if ($postdata[$key] == 'blob-storage')
                    {
                        unset($postdata[$key]);
                        continue;
                    } else
                    {
                        $folder = isset($this->upload_folder[$key]) ? $this->upload_folder[$key] : $this->upload_folder_def;
                        $path = realpath($folder) . '/' . $postdata[$key];
                        $postdata[$key] = file_get_contents($path);
                        @unlink($path);
                    }
                }
            }
        }
        if (!$primary)
        {
            if (!$this->is_add)
                return $this->error('Forbidden');
            if ($this->pass_var_create)
            {
                foreach ($this->pass_var_create as $field => $value)
                {
                    $postdata[$field] = $value;
                }
            }
            if ($this->alert_create)
            {
                foreach ($this->alert_create as $alert)
                {
                    if ($alert['field'] && isset($postdata[$alert['field']]) && $postdata[$alert['field']] != $alert['value'])
                        continue;
                    if (!isset($postdata[$alert['column']]) or !preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/',
                        $postdata[$alert['column']]))
                        continue;
                    foreach ($postdata as $m_field => $m_value)
                    {
                        $alert['message'] = str_ireplace('{' . $m_field . '}', $m_value, $alert['message']);
                    }
                    if (Xcrud_config::$email_enable_html)
                        $message = $alert['message'] . '<br /><br />' . "\r\n" . ($alert['link'] ? '<a href="' . $alert['link'] .
                            '" target="_blank">' . $alert['link'] . '</a>' : '');
                    else
                        $message = $alert['message'] . "\r\n\r\n" . ($alert['link'] ? $alert['link'] : '');
                    $this->send_email($postdata[$alert['column']], $alert['subject'], $message, $alert['cc'], Xcrud_config::$email_enable_html);
                }
            }
            if ($this->before_insert)
            {
                include_once (realpath($this->before_insert['lib']));
                $callable = $this->before_insert['class'] ? array($this->before_insert['class'], $this->before_insert['func']) : $this->
                    before_insert['func'];
                if (is_callable($callable))
                {
                    $postdata = call_user_func_array($callable, array($postdata));
                }
            }
            $primary = $this->_insert($postdata);
            if ($this->after_insert)
            {
                include_once (realpath($this->after_insert['lib']));
                $callable = $this->after_insert['class'] ? array($this->after_insert['class'], $this->after_insert['func']) : $this->
                    after_insert['func'];
                if (is_callable($callable))
                {
                    call_user_func_array($callable, array($postdata, $primary));
                }
            }
        } else
        {
            if (!$this->is_edit)
                return $this->error('Forbidden');
            if ($this->pass_var_edit)
            {
                foreach ($this->pass_var_edit as $field => $value)
                {
                    $postdata[$field] = $value;
                }
            }
            if ($this->alert_edit)
            {
                foreach ($this->alert_edit as $alert)
                {
                    if ($alert['field'] && isset($postdata[$alert['field']]) && $postdata[$alert['field']] != $alert['value'])
                        continue;
                    if (!isset($postdata[$alert['column']]) or !preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/',
                        $postdata[$alert['column']]))
                        continue;
                    foreach ($postdata as $m_field => $m_value)
                    {
                        $alert['message'] = str_ireplace('{' . $m_field . '}', $m_value, $alert['message']);
                    }
                    if (Xcrud_config::$email_enable_html)
                        $message = $alert['message'] . '<br /><br />' . "\r\n" . ($alert['link'] ? '<a href="' . $alert['link'] .
                            '" target="_blank">' . $alert['link'] . '</a>' : '');
                    else
                        $message = $alert['message'] . "\r\n\r\n" . ($alert['link'] ? $alert['link'] : '');
                    $this->send_email($postdata[$alert['column']], $alert['subject'], $message, $alert['cc'], Xcrud_config::$email_enable_html);
                }
            }
            if ($this->before_update)
            {
                include_once (realpath($this->before_update['lib']));
                $callable = $this->before_update['class'] ? array($this->before_update['class'], $this->before_update['func']) : $this->
                    before_update['func'];
                if (is_callable($callable))
                {
                    $postdata = call_user_func_array($callable, array($postdata, $primary));
                }
            }
            $primary = $this->_update($postdata, $primary);
            if ($this->after_update)
            {
                include_once (realpath($this->after_update['lib']));
                $callable = $this->after_update['class'] ? array($this->after_update['class'], $this->after_update['func']) : $this->
                    after_update['func'];
                if (is_callable($callable))
                {
                    call_user_func_array($callable, array($postdata, $primary));
                }
            }
        }
        unset($postdata);
        return $primary;
    }
    protected function _list()
    {
        $this->_set_column_names();
        $select = $this->_build_select_list();
        $join = $this->_build_join();
        $where = $this->_build_where();
        $order_by = $this->_build_order_by();
        if ($this->sum)
        {
            foreach ($this->sum as $field => $table)
            {
                if (!$table)
                    $table = $this->table;
                $this->sum[$field] = "SUM(`{$table}`.`{$field}`) AS `{$field}`";
            }
        }
        $sum = $this->sum ? ', ' . implode(', ', $this->sum) : '';
        $db = Xcrud_db::get_instance($this->connection);
        $db->query("SELECT COUNT(`{$this->table}`.`{$this->primary}`) AS `count` {$sum} \r\n FROM `{$this->table}` \r\n {$join} {$where}");
        $this->sum_row = $db->row();
        $total = $this->sum_row->count;
        $limit = $this->_build_limit($total);
        $db->query("SELECT {$select} \r\n FROM `{$this->table}` \r\n {$join} {$where} \r\n {$order_by} {$limit}");
        $list = $db->result();
        return $this->_render_list($list, $total);
    }
    protected function _build_select_list($csv = false)
    {
        $columns = array();
        foreach ($this->columns as $key => $val)
        {
            $val = trim($val);
            if (isset($this->join[$val]))
            {
                if (is_array($this->join[$val]['rel_name']))
                {
                    $tmp_fields = array();
                    foreach ($this->join[$val]['rel_name'] as $tmp)
                    {
                        $tmp_fields[] = "`{$this->join[$val]['rel_alias']}`.`{$tmp}` \r\n";
                    }
                    $columns[$key] = "CONCAT_WS('{$this->join[$val]['rel_separator']}'," . implode(',', $tmp_fields) . ") AS `{$val}` \r\n";
                } else
                    $columns[$key] = "`{$this->join[$val]['rel_alias']}`.`{$this->join[$val]['rel_name']}` AS `{$val}` \r\n";
            } else
            {
                if (mb_strpos($val, '.', 0, Xcrud_config::$mbencoding))
                {
                    list($table, $val) = explode('.', $val, 2);
                    $columns[$key] = "`{$table}`.`{$val}` AS `{$table}_{$val}` \r\n";
                } else
                    $columns[$key] = "`{$this->table}`.`{$val}` \r\n";
            }
        }
        if (!$csv)
            $columns[] = "`{$this->table}`.`{$this->primary}` AS `primary_key` \r\n";
        return implode(',', $columns);
    }
    protected function _build_select_details()
    {
        $fields = array();
        if ($this->inner_table_instance)
        {
            foreach ($this->inner_table_instance as $field => $val)
            {
                if (!in_array($field, $this->fields))
                {
                    $this->fields[] = $field;
                    $this->field_type[$field] = 'hidden';
                }
            }
        }
        foreach ($this->fields as $key => $val)
        {
            $val = trim($val);
            if (mb_strpos($val, '.', 0, Xcrud_config::$mbencoding))
            {
                list($table, $val) = explode('.', $val, 2);
                $fields[$key] = "`{$table}`.`{$val}` AS `{$table}_{$val}`";
            } else
                $fields[$key] = "`{$this->table}`.`{$val}`";
        }
        $fields[] = "`{$this->table}`.`{$this->primary}` AS `primary_key`";
        return implode(',', $fields);
    }
    protected function _build_join()
    {
        $join = '';
        if (count($this->table_join))
        {
            $join_arr = array();
            foreach ($this->table_join as $table => $params)
            {
                $join_arr[] = "INNER JOIN `{$table}` ON `{$this->table}`.`{$params['field']}` = `{$table}`.`{$params['join_field']}`";
            }
            $join .= implode(' ', $join_arr);
        }
        if (count($this->join))
        {
            $join_arr = array();
            foreach ($this->join as $field => $params)
            {
                $join_arr[] = "LEFT JOIN `{$params['rel_tbl']}` AS `{$params['rel_alias']}` ON `{$this->table}`.`{$field}` = `{$params['rel_alias']}`.`{$params['rel_field']}` \r\n";
            }
            $join .= implode(' ', $join_arr);
        }
        return $join;
    }
    protected function _build_where($join = true)
    {
        $db = Xcrud_db::get_instance($this->connection);
        $where_arr = array();
        if (count($this->where))
        {
            foreach ($this->where as $field => $val)
            {
                if ($val or is_int($val) or is_float($val))
                {
                    if (mb_strpos($field, '.', 0, Xcrud_config::$mbencoding))
                    {
                        list($table, $field) = explode('.', $field, 2);
                        $where_arr[] = "`{$table}`." . $this->_prepare_field($field) . (isset($this->no_quotes[$field]) ? $db->escape($val, true) :
                            $db->escape($val));
                    } else
                        $where_arr[] = "`{$this->table}`." . $this->_prepare_field($field) . (isset($this->no_quotes[$field]) ? $db->escape($val, true) :
                            $db->escape($val));
                } else
                {
                    $where_arr[] = $field;
                }
            }
        }
        if (count($this->join) && $join)
        {
            foreach ($this->join as $params)
            {
                if (is_array($params['rel_where']))
                {
                    foreach ($params['rel_where'] as $field => $val)
                    {
                        if ($val or is_int($val) or is_float($val))
                        {
                            if (mb_strpos($field, '.', 0, Xcrud_config::$mbencoding))
                            {
                                list($table, $field) = explode('.', $field, 2);
                                $where_arr[] = "`{$table}`." . $this->_prepare_field($field) . (isset($this->no_quotes[$field]) ? $db->escape($val, true) :
                                    $db->escape($val));
                            } else
                                $where_arr[] = "`{$params['rel_alias']}`." . $this->_prepare_field($field) . (isset($this->no_quotes[$field]) ? $db->
                                    escape($val, true) : $db->escape($val));
                        } else
                        {
                            $where_arr[] = $field;
                        }
                    }
                } else
                    $where_arr[] = $params['rel_where'];
            }
        }
        $phrase = $this->_post('phrase');
        if ($phrase && ($this->_post('task') == 'list' or $this->_post('task') == 'print' or $this->_post('after') == 'list'))
        {
            $column = $this->_post('column');
            if (mb_strpos($column, '.', 0, Xcrud_config::$mbencoding))
                list($table, $column) = explode('.', $column, 2);
            else
                $table = $this->table;

            if (isset($this->join[$column]) && in_array($column, $this->columns))
            {
                if (is_array($this->join[$column]['rel_name']))
                {
                    $tmp_fields = array();
                    foreach ($this->join[$column]['rel_name'] as $tmp)
                    {
                        $tmp_fields[] = "`{$this->join[$column]['rel_alias']}`.`$tmp`";
                    }
                    $where_arr[] = "CONCAT_WS('{$this->join[$column]['rel_separator']}'," . implode(',', $tmp_fields) . ") LIKE " . $db->
                        escape_like($phrase, $this->search_pattern);
                } else
                    $where_arr[] = "`{$this->join[$column]['rel_alias']}`.`{$this->join[$column]['rel_name']}` LIKE " . $db->escape_like($phrase,
                        $this->search_pattern);
            } else
                $where_arr[] = "`{$table}`.`{$column}` LIKE " . $db->escape_like($phrase, $this->search_pattern);
        }
        if (count($where_arr))
            return 'WHERE ' . implode(' AND ', $where_arr);
        else
            return '';
    }
    protected function _receive_post()
    {
        if ($this->_post('order'))
        {
            $field = $this->_post('order');
            $direction = $this->_post('direct') == 'desc' ? 'desc' : 'asc';
            if (isset($this->order_by[$field]))
                unset($this->order_by[$field]);
            $this->order_by = array_merge(array($field => $direction), $this->order_by);
        }
    }
    protected function _build_order_by()
    {
        if (count($this->order_by))
        {
            $order_arr = array();
            foreach ($this->order_by as $field => $direction)
            {
                if (mb_strpos($field, '.', 0, Xcrud_config::$mbencoding))
                {
                    list($table, $field) = explode('.', $field, 2);
                } else
                    $table = $this->table;
                if (isset($this->join[$field]) && in_array($field, $this->columns)) // proper sort on rel name

                    $order_arr[] = "`{$field}` {$direction}";
                else
                    $order_arr[] = "`{$table}`.`{$field}` {$direction}";
            }
            return 'ORDER BY ' . implode(',', $order_arr);
        } else
        {
            $this->order_by[$this->primary] = 'asc';
            return "ORDER BY `{$this->table}`.`{$this->primary}` asc";
        }
    }
    protected function _build_limit($total)
    {
        $start = $this->_post('start') ? $this->_post('start') : 0;
        $limit = $this->_post('limit') ? $this->_post('limit') : $this->limit;
        if ($limit != 'all' && $this->theme != 'printout')
        {
            if ($start > 0 && $start >= $total)
            {
                $start = $total > $limit ? $total - $limit : 0;
            }
            $start = floor($start / $limit) * $limit;
            return "LIMIT {$start},{$limit}";
        } else
            return '';
    }
    protected function _table_info()
    {
        $db = Xcrud_db::get_instance($this->connection);
        $db->query("SHOW COLUMNS FROM `{$this->table}`");
        return $db->result();
    }
    protected function _set_field_types($types_array)
    {
        if (is_array($types_array) && count($types_array))
        {
            $uni = false;
            $pri = false;
            $fields = array();
            foreach ($types_array as $row)
            {
                if ($row->Key == 'PRI' or $row->Key == 'UNI')
                    $this->unique[$row->Field] = true;
                if ($row->Key == 'PRI' && $row->Extra == 'auto_increment')
                {
                    if (!$this->primary)
                        $this->primary = $row->Field;
                    if (!$this->show_primary_ai_field)
                    {
                        continue;
                    }
                    $this->disabled_on_create[$row->Field] = true;
                    $this->disabled_on_edit[$row->Field] = true;
                    $fields[] = $row->Field;
                }
                if ($row->Key == 'UNI' && !$uni)
                {
                    $uni = $row->Field;
                }
                if ($row->Key == 'PRI' && !$pri)
                {
                    $pri = $row->Field;
                }
                if ($this->fields && !in_array($row->Field, $this->fields) && !$this->reverse_fields)
                    continue;
                elseif ($this->fields && in_array($row->Field, $this->fields) && $this->reverse_fields)
                    continue;
                if (isset($this->join[$row->Field]))
                {
                    $this->field_type[$row->Field] = 'relation';
                    if (!isset($this->defaults[$row->Field]))
                        $this->defaults[$row->Field] = $row->Default;
                    $fields[] = $row->Field;
                    continue;
                }
                if (!isset($this->field_type[$row->Field]))
                {
                    $fields[] = $row->Field;
                    if (mb_strpos($row->Type, '(') === false)
                    {
                        $type = $row->Type;
                    } else
                    {
                        $l_pos = mb_strpos($row->Type, '(');
                        $r_pos = mb_strpos($row->Type, ')');
                        $type = mb_substr($row->Type, 0, $l_pos);
                        $max_l = mb_substr($row->Type, $l_pos + 1, $r_pos - $l_pos - 1);
                    }
                    switch ($type)
                    {
                        case 'tinyint':
                        case 'bit':
                        case 'bool':
                        case 'boolean':
                            if ($max_l == 1 && Xcrud_config::$make_checkbox)
                            {
                                $this->field_type[$row->Field] = 'bool';
                                if (!isset($this->defaults[$row->Field]))
                                    $this->defaults[$row->Field] = $row->Default;
                            } else
                            {
                                $this->field_type[$row->Field] = 'int';
                                $this->field_maxsize[$row->Field] = (int)$max_l;
                                if (!isset($this->defaults[$row->Field]))
                                    $this->defaults[$row->Field] = $row->Default;
                            }
                            break;
                        case 'smallint':
                        case 'mediumint':
                        case 'int':
                        case 'bigint':
                        case 'serial':
                            $this->field_type[$row->Field] = 'int';
                            $this->field_maxsize[$row->Field] = (int)$max_l;
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'decimal':
                        case 'numeric':
                        case 'float':
                        case 'double':
                        case 'real':
                            $this->field_type[$row->Field] = 'float';
                            $this->field_maxsize[$row->Field] = (int)$max_l;
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'char':
                        case 'varchar':
                        case 'binary':
                        case 'varbinary':
                        default:
                            $this->field_type[$row->Field] = 'text';
                            $this->field_maxsize[$row->Field] = (int)$max_l;
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'text':
                        case 'tynytext':
                        case 'mediumtext':
                        case 'longtext':
                            if (!isset($this->no_editor[$row->Field]))
                                $this->field_type[$row->Field] = 'texteditor';
                            else
                                $this->field_type[$row->Field] = 'textarea';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'blob':
                        case 'tynyblob':
                        case 'mediumblob':
                        case 'longblob':
                            $this->field_type[$row->Field] = 'binary';
                            $this->defaults[$row->Field] = '';
                            break;
                        case 'date':
                            $this->field_type[$row->Field] = 'date';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'datetime':
                            $this->field_type[$row->Field] = 'datetime';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'timestamp':
                            $this->field_type[$row->Field] = 'timestamp';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = date('Y:m:d H:i:s');
                            break;
                        case 'time':
                            $this->field_type[$row->Field] = 'time';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'year':
                            $this->field_type[$row->Field] = 'year';
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'enum':
                            $this->field_type[$row->Field] = 'select';
                            $this->field_maxsize[$row->Field] = $max_l;
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                        case 'set':
                            $this->field_type[$row->Field] = 'multiselect';
                            $this->field_maxsize[$row->Field] = $max_l;
                            if (!isset($this->defaults[$row->Field]))
                                $this->defaults[$row->Field] = $row->Default;
                            break;
                    }
                } else
                    $fields[] = $row->Field;
            }
            if (!$this->fields or $this->reverse_fields)
                $this->fields = $fields;
            if (!$this->primary)
            {
                if ($uni)
                    $this->primary = $uni;
                else
                    if ($pri)
                        $this->primary = $pri;
                    else
                        $this->primary = $types_array[0]->Field;
                if (!$this->show_primary_ai_field && isset($this->fields[$this->primary]))
                    unset($this->fields[$this->primary]);
            }
            unset($fields, $types_array);
        }
    }
    protected function _set_columns($types_array, $check_dub_avail = false)
    {
        if (is_array($types_array) && count($types_array))
        {
            $columns = array();
            $uni = false;
            $pri = false;
            if ($check_dub_avail)
            {
                $this->primary_ai = false;
                $this->unique_ind = array();
                $this->clone_fields = array();
            }
            foreach ($types_array as $row)
            {
                if ($row->Key == 'PRI' && $row->Extra == 'auto_increment')
                {
                    if ($check_dub_avail)
                        $this->primary_ai = $row->Key;
                    if (!$this->primary)
                        $this->primary = $row->Field;
                    if (!$this->show_primary_ai_column)
                        continue;
                } elseif ($check_dub_avail)
                {
                    $this->clone_fields[] = $row->Field;
                }
                if ($row->Key == 'UNI' && !$uni)
                {
                    $uni = $row->Field;
                    if ($check_dub_avail)
                        $this->unique_ind[] = $row->Field;
                }
                if ($row->Key == 'PRI' && !$pri)
                {
                    $pri = $row->Field;
                    if ($check_dub_avail)
                        $this->unique_ind[] = $row->Field;
                }
                if (strstr($row->Type, 'blob'))
                {
                    $this->binary[$row->Field] = true;
                }
                if (!$this->columns)
                {
                    $columns[] = $row->Field;
                } elseif ($this->columns && $this->reverse_columns)
                {
                    if (in_array($row->Field, $this->columns))
                    {
                        $key = array_search($row->Field, $this->columns);
                        unset($this->columns[$key]);
                    } else
                        $columns[] = $row->Field;
                }
                ######################
                if (isset($this->join[$row->Field]))
                {
                    $this->field_type[$row->Field] = 'relation';
                    continue;
                }
                if (!isset($this->field_type[$row->Field]))
                {
                    if (mb_strpos($row->Type, '(') === false)
                    {
                        $type = $row->Type;
                    } else
                    {
                        $l_pos = mb_strpos($row->Type, '(');
                        $r_pos = mb_strpos($row->Type, ')');
                        $type = mb_substr($row->Type, 0, $l_pos);
                        $max_l = mb_substr($row->Type, $l_pos + 1, $r_pos - $l_pos - 1);
                    }
                    switch ($type)
                    {
                        case 'tinyint':
                        case 'bit':
                        case 'bool':
                        case 'boolean':
                            if ($max_l == 1 && Xcrud_config::$make_checkbox)
                            {
                                $this->field_type[$row->Field] = 'bool';
                            } else
                            {
                                $this->field_type[$row->Field] = 'int';
                            }
                            break;
                        case 'smallint':
                        case 'mediumint':
                        case 'int':
                        case 'bigint':
                        case 'serial':
                            $this->field_type[$row->Field] = 'int';
                            break;
                        case 'decimal':
                        case 'numeric':
                        case 'float':
                        case 'double':
                        case 'real':
                            $this->field_type[$row->Field] = 'float';
                            break;
                        case 'char':
                        case 'varchar':
                        case 'binary':
                        case 'varbinary':
                        default:
                            $this->field_type[$row->Field] = 'text';
                            break;
                        case 'text':
                        case 'tynytext':
                        case 'mediumtext':
                        case 'longtext':
                            if (!isset($this->no_editor[$row->Field]))
                                $this->field_type[$row->Field] = 'texteditor';
                            else
                                $this->field_type[$row->Field] = 'textarea';
                            break;
                        case 'blob':
                        case 'tynyblob':
                        case 'mediumblob':
                        case 'longblob':
                            $this->field_type[$row->Field] = 'binary';
                            break;
                        case 'date':
                            $this->field_type[$row->Field] = 'date';
                            break;
                        case 'datetime':
                            $this->field_type[$row->Field] = 'datetime';
                            break;
                        case 'timestamp':
                            $this->field_type[$row->Field] = 'timestamp';
                            break;
                        case 'time':
                            $this->field_type[$row->Field] = 'time';
                            break;
                        case 'year':
                            $this->field_type[$row->Field] = 'year';
                            break;
                        case 'enum':
                            $this->field_type[$row->Field] = 'select';
                            $this->field_maxsize[$row->Field] = $max_l;
                            break;
                        case 'set':
                            $this->field_type[$row->Field] = 'multiselect';
                            $this->field_maxsize[$row->Field] = $max_l;
                            break;
                    }
                }
                ######################
            }
            if (!$this->columns or $this->reverse_columns)
                $this->columns = $columns;
            if (!$this->primary)
            {
                if ($uni)
                    $this->primary = $uni;
                else
                    if ($pri)
                        $this->primary = $pri;
                    else
                        $this->primary = $types_array[0]->Field;
                if (!$this->show_primary_ai_column && isset($this->columns[$this->primary]))
                    unset($this->columns[$this->primary]);
            }
        }
    }
    protected function _set_column_names()
    {
        foreach ($this->columns as $col)
        {
            if (isset($this->labels[$col]))
                $this->columns_names[$col] = $this->html_safe($this->labels[$col]);
            else
                $this->columns_names[$col] = $this->html_safe($this->_humanize($col));
        }
    }
    protected function _set_field_names()
    {
        foreach ($this->fields as $field)
        {
            if (isset($this->labels[$field]))
                $this->fields_names[$field] = $this->html_safe($this->labels[$field]) . (isset($this->validation_required[$field]) ?
                    '&#42;' : '');
            else
                $this->fields_names[$field] = $this->html_safe($this->_humanize($field)) . (isset($this->validation_required[$field]) ?
                    '&#42;' : '');
        }
    }
    protected function _render_list($list, $total)
    {
        if (count($this->order_by))
        {
            reset($this->order_by);
            $order_column = key($this->order_by);
            $order_direct = $this->order_by[$order_column];
        } else
        {
            $order_column = $this->primary;
            $order_direct = 'asc';
        }
        $start = $this->_post('start') ? $this->_post('start') : 0;
        $limit = $this->_post('limit') ? $this->_post('limit') : $this->limit;
        $total_columns = count($this->columns);
        if ($start > 0 && $start >= $total)
            $start = $total > $limit ? $total - $limit : 0;
        $start = ($limit != 'all') ? floor($start / $limit) * $limit : 'all';
        $phrase = $this->_post('phrase');
        $column = $this->_post('column');
        $pagination = $this->_pagination($total, $start, $limit);
        $this->_export_special();
        ob_start();
        include ($this->self_path . '/themes/' . $this->theme . '/xcrud_list_view.php');
        $out = ob_get_contents();
        ob_end_clean();
        return $out;
    }
    protected function _render_details($list, $mode)
    {
        $fields = array();
        if (count($this->order_by))
        {
            reset($this->order_by);
            $order_column = key($this->order_by);
            $order_direct = $this->order_by[$order_column];
        } else
        {
            $order_column = $this->primary;
            $order_direct = 'asc';
        }
        $order_column = $this->_post('order');
        $order_direct = $this->_post('direct');
        $start = $this->_post('start');
        $limit = $this->_post('limit');
        $total_columns = count($this->columns);
        $phrase = $this->_post('phrase');
        $column = $this->_post('column');
        $disabled = 'disabled_on_' . $mode;
        $readonly = 'readonly_on_' . $mode;
        $this->disabled = $this->$disabled;
        $this->readonly = $this->$readonly;
        if ($list)
        {
            foreach ($list as $key => $val)
            {
                if (isset($this->inner_table_instance[$key]))
                {
                    $this->inner_table_instance[$key] = Xcrud::get_instance($this->instance_name() . '_inner_' . $key);
                    $this->inner_table_instance[$key]->_import_vars();
                    $this->inner_table_instance[$key]->where($this->inner_where[$key], $val);
                    $this->inner_table_instance[$key]->pass_default($this->inner_where[$key], $val);
                }
                if ($key == 'primary_key')
                {
                    $this->primary_key = $val;
                    continue;
                }
                if ($this->field_type[$key] != 'hidden')
                {
                    $func = 'create_' . $this->field_type[$key];
                    if (!method_exists($this, $func))
                        continue;
                    $fields[] = array(
                        'label' => $this->fields_names[$key],
                        'field' => $this->$func($key, $val),
                        'name' => $key);
                } else
                    $hidden_fields[] = $this->create_hidden($key, $val);
            }
        }
        $this->_export_special();
        ob_start();
        include ($this->self_path . '/themes/' . $this->theme . '/xcrud_details_view.php');
        $out = ob_get_contents();
        ob_end_clean();
        if ($this->inner_table_instance)
        {
            foreach ($this->inner_table_instance as $key => $instance)
            {
                $out .= '<div class="xcrud"><div class="xcrud-container">' . $this->inner_table_instance[$key]->render_inner() .
                    '</div></div>';
            }
        }
        return $out;
    }
    protected function _pagination($total, $start, $limit)
    {
        if ($total > $limit)
        {
            $pages = ceil($total / $limit);
            $curent = ceil(($start + $limit) / $limit);
            $links = array();
            for ($i = 1; $i <= $pages; ++$i)
            {
                $limit1 = $i * $limit - $limit;
                if ($i == $curent)
                    $links[$i] = '<li><span>' . $i . '</span></li>';
                else
                {
                    $links[$i] = '<li><a href="javascript:void(0);" data-start="' . $limit1 . '">' . $i . '</a></li>';
                }
            }

            $numlr = 2;
            $numpos = 10;
            $html = '<span class="xcrud-pagination pagination"><ul>';
            if ($pages > $numpos)
            {

                if ($curent <= $numlr + 3)
                {
                    for ($i = 1; $i <= $numpos - $numlr - 1; ++$i)
                    {
                        $html .= $links[$i];
                    }
                    $html .= '<li><span>&#133;</span></li>';
                    for ($i = $pages - $numlr + 1; $i <= $pages; ++$i)
                    {
                        $html .= $links[$i];
                    }
                } else
                    if ($curent >= $pages - $numlr - 2)
                    {
                        for ($i = 1; $i <= $numlr; ++$i)
                        {
                            $html .= $links[$i];
                        }
                        $html .= '<li><span>&#133;</span></li>';
                        for ($i = $pages - $numpos + $numlr + 2; $i <= $pages; ++$i)
                        {
                            $html .= $links[$i];
                        }
                    } else
                    {
                        for ($i = 1; $i <= $numlr; ++$i)
                        {
                            $html .= $links[$i];
                        }
                        $html .= '<li><span>&#133;</span></li>';
                        $offset = floor(($numpos - $numlr - $numlr - 1) / 2);
                        for ($i = $curent - $offset; $i <= $curent + $offset; ++$i)
                        {
                            $html .= $links[$i];
                        }

                        $html .= '<li><span>&#133;</span></li>';
                        for ($i = $pages - $numlr + 1; $i <= $pages; ++$i)
                        {
                            $html .= $links[$i];
                        }
                    }

            } else
            {
                $html .= implode('', $links);
            }
            $html .= '</ul></span>';
            return $html;
        }
    }
    protected function _cut($string, $len, $wordsafe = true, $dots = true)
    {
        $string = trim(strip_tags($string));
        $slen = mb_strlen($string, Xcrud_config::$mbencoding);
        if ($slen <= $len)
        {
            return $this->html_safe($string);
        }
        if ($wordsafe)
        {
            $end = $len;
            while ((mb_substr($string, --$len, 1, Xcrud_config::$mbencoding) != ' ') && ($len > 0))
            {
            }
            ;
            if ($len == 0)
            {
                $len = $end;
            }
            return $this->html_safe(mb_substr($string, 0, $len, Xcrud_config::$mbencoding)) . ($dots ? '&#133;' : '');
        }
        return $this->html_safe(mb_substr($string, 0, $len, Xcrud_config::$mbencoding)) . ($dots ? '&#133;' : '');
    }
    protected function _humanize($text)
    {
        return mb_convert_case(str_replace('_', ' ', $text), MB_CASE_TITLE, Xcrud_config::$mbencoding);
    }
    protected function _regenerate_key()
    {
        return sha1(microtime() . rand(0, 999));
    }
    protected function _export_inner_vars()
    {
        if ($this->inner_table_instance)
        {
            foreach ($this->inner_table_instance as $name => $instanse)
            {
                $instanse->_export_vars();
            }
        }
    }
    public function _export_vars($inst_name = '')
    {
        if (!$inst_name)
            $inst_name = $this->instance_name();
        $_SESSION['xcrud_' . $inst_name] = array(
            'key' => $this->key,
            'table' => $this->table,
            'table_name' => $this->table_name,
            'where' => $this->where,
            'order_by' => $this->order_by,
            'join' => $this->join,
            'fields' => $this->fields,
            'labels' => $this->labels,
            'columns' => $this->columns,
            'columns_names' => $this->columns_names,
            'is_add' => $this->is_add,
            'is_edit' => $this->is_edit,
            'is_remove' => $this->is_remove,
            'is_csv' => $this->is_csv,
            'buttons' => $this->buttons,
            'validation_required' => $this->validation_required,
            'validation_pattern' => $this->validation_pattern,
            'before_insert' => $this->before_insert,
            'before_update' => $this->before_update,
            'before_remove' => $this->before_remove,
            'sess_expire' => $this->sess_expire,
            'after_insert' => $this->after_insert,
            'after_update' => $this->after_update,
            'after_remove' => $this->after_remove,
            'field_type' => $this->field_type,
            'field_maxsize' => $this->field_maxsize,
            'limit' => $this->limit,
            'limit_list' => $this->limit_list,
            'column_cut' => $this->column_cut,
            'no_editor' => $this->no_editor,
            'crud_url' => $this->crud_url,
            'show_primary_ai_field' => $this->show_primary_ai_field,
            'show_primary_ai_column' => $this->show_primary_ai_column,
            'disabled_on_create' => $this->disabled_on_create,
            'disabled_on_edit' => $this->disabled_on_edit,
            'readonly_on_create' => $this->readonly_on_create,
            'readonly_on_edit' => $this->readonly_on_edit,
            'benchmark' => $this->benchmark,
            'search_pattern' => $this->search_pattern,
            'connection' => $this->connection,
            'remove_confirm' => $this->remove_confirm,
            'upload_folder' => $this->upload_folder,
            'upload_config' => $this->upload_config,
            'pass_var_create' => $this->pass_var_create,
            'pass_var_edit' => $this->pass_var_edit,
            'reverse_columns' => $this->reverse_columns,
            'reverse_fields' => $this->reverse_fields,
            'no_quotes' => $this->no_quotes,
            'inner_table_instance' => $this->inner_table_instance,
            'inner_where' => $this->inner_where,
            'unique' => $this->unique,
            'theme' => $this->theme,
            'is_duplicate' => $this->is_duplicate,
            'links_label' => $this->links_label,
            'emails_label' => $this->emails_label,
            'sum' => $this->sum,
            'alert_create' => $this->alert_create,
            'alert_edit' => $this->alert_edit,
            'is_search' => $this->is_search,
            'is_print' => $this->is_print);

        $this->_export_special();
    }
    protected function _export_special()
    {
        $_SESSION['xcrud_' . $this->instance_name()] = array_merge($_SESSION['xcrud_' . $this->instance_name()], array(
            'upload_to_save' => $this->upload_to_save,
            'upload_to_remove' => $this->upload_to_remove,
            'primary_key' => $this->primary_key,
            'primary' => $this->primary,
            'defaults' => $this->defaults));
    }
    protected function _direct_export($param = '', $value = '')
    {
        $_SESSION['xcrud_' . $this->instance_name()][$param] = $value;
    }
    public function _import_vars($instanse_name = '')
    {
        if (!$instanse_name)
            $instanse_name = $this->instance_name();

        $this->table = $_SESSION['xcrud_' . $instanse_name]['table'];
        $this->table_name = $_SESSION['xcrud_' . $instanse_name]['table_name'];
        $this->primary = $_SESSION['xcrud_' . $instanse_name]['primary'];
        $this->where = $_SESSION['xcrud_' . $instanse_name]['where'];
        $this->order_by = $_SESSION['xcrud_' . $instanse_name]['order_by'];
        $this->join = $_SESSION['xcrud_' . $instanse_name]['join'];
        $this->fields = $_SESSION['xcrud_' . $instanse_name]['fields'];
        $this->labels = $_SESSION['xcrud_' . $instanse_name]['labels'];
        $this->columns = $_SESSION['xcrud_' . $instanse_name]['columns'];
        $this->columns_names = $_SESSION['xcrud_' . $instanse_name]['columns_names'];
        $this->is_add = $_SESSION['xcrud_' . $instanse_name]['is_add'];
        $this->is_edit = $_SESSION['xcrud_' . $instanse_name]['is_edit'];
        $this->is_remove = $_SESSION['xcrud_' . $instanse_name]['is_remove'];
        $this->is_csv = $_SESSION['xcrud_' . $instanse_name]['is_csv'];
        $this->buttons = $_SESSION['xcrud_' . $instanse_name]['buttons'];
        $this->validation_required = $_SESSION['xcrud_' . $instanse_name]['validation_required'];
        $this->validation_pattern = $_SESSION['xcrud_' . $instanse_name]['validation_pattern'];
        $this->before_insert = $_SESSION['xcrud_' . $instanse_name]['before_insert'];
        $this->before_update = $_SESSION['xcrud_' . $instanse_name]['before_update'];
        $this->before_remove = $_SESSION['xcrud_' . $instanse_name]['before_remove'];
        $this->sess_expire = $_SESSION['xcrud_' . $instanse_name]['sess_expire'];
        $this->after_insert = $_SESSION['xcrud_' . $instanse_name]['after_insert'];
        $this->after_update = $_SESSION['xcrud_' . $instanse_name]['after_update'];
        $this->after_remove = $_SESSION['xcrud_' . $instanse_name]['after_remove'];
        $this->field_type = $_SESSION['xcrud_' . $instanse_name]['field_type'];
        $this->field_maxsize = $_SESSION['xcrud_' . $instanse_name]['field_maxsize'];
        $this->limit = $_SESSION['xcrud_' . $instanse_name]['limit'];
        $this->limit_list = $_SESSION['xcrud_' . $instanse_name]['limit_list'];
        $this->column_cut = $_SESSION['xcrud_' . $instanse_name]['column_cut'];
        $this->no_editor = $_SESSION['xcrud_' . $instanse_name]['no_editor'];
        $this->crud_url = $_SESSION['xcrud_' . $instanse_name]['crud_url'];
        $this->show_primary_ai_field = $_SESSION['xcrud_' . $instanse_name]['show_primary_ai_field'];
        $this->show_primary_ai_column = $_SESSION['xcrud_' . $instanse_name]['show_primary_ai_column'];
        $this->disabled_on_create = $_SESSION['xcrud_' . $instanse_name]['disabled_on_create'];
        $this->disabled_on_edit = $_SESSION['xcrud_' . $instanse_name]['disabled_on_edit'];
        $this->readonly_on_create = $_SESSION['xcrud_' . $instanse_name]['readonly_on_create'];
        $this->readonly_on_edit = $_SESSION['xcrud_' . $instanse_name]['readonly_on_edit'];
        $this->benchmark = $_SESSION['xcrud_' . $instanse_name]['benchmark'];
        $this->search_pattern = $_SESSION['xcrud_' . $instanse_name]['search_pattern'];
        $this->connection = $_SESSION['xcrud_' . $instanse_name]['connection'];
        $this->remove_confirm = $_SESSION['xcrud_' . $instanse_name]['remove_confirm'];
        $this->upload_folder = $_SESSION['xcrud_' . $instanse_name]['upload_folder'];
        $this->upload_config = $_SESSION['xcrud_' . $instanse_name]['upload_config'];
        $this->upload_to_save = $_SESSION['xcrud_' . $instanse_name]['upload_to_save'];
        $this->upload_to_remove = $_SESSION['xcrud_' . $instanse_name]['upload_to_remove'];
        $this->primary_key = $_SESSION['xcrud_' . $instanse_name]['primary_key'];
        $this->defaults = $_SESSION['xcrud_' . $instanse_name]['defaults'];
        $this->pass_var_create = $_SESSION['xcrud_' . $instanse_name]['pass_var_create'];
        $this->pass_var_edit = $_SESSION['xcrud_' . $instanse_name]['pass_var_edit'];
        $this->reverse_columns = $_SESSION['xcrud_' . $instanse_name]['reverse_columns'];
        $this->reverse_fields = $_SESSION['xcrud_' . $instanse_name]['reverse_fields'];
        $this->no_quotes = $_SESSION['xcrud_' . $instanse_name]['no_quotes'];
        $this->inner_table_instance = $_SESSION['xcrud_' . $instanse_name]['inner_table_instance'];
        $this->inner_where = $_SESSION['xcrud_' . $instanse_name]['inner_where'];
        $this->unique = $_SESSION['xcrud_' . $instanse_name]['unique'];
        $this->theme = $_SESSION['xcrud_' . $instanse_name]['theme'];
        $this->is_duplicate = $_SESSION['xcrud_' . $instanse_name]['is_duplicate'];
        $this->links_label = $_SESSION['xcrud_' . $instanse_name]['links_label'];
        $this->emails_label = $_SESSION['xcrud_' . $instanse_name]['emails_label'];
        $this->sum = $_SESSION['xcrud_' . $instanse_name]['sum'];
        $this->alert_create = $_SESSION['xcrud_' . $instanse_name]['alert_create'];
        $this->alert_edit = $_SESSION['xcrud_' . $instanse_name]['alert_edit'];
        $this->is_search = $_SESSION['xcrud_' . $instanse_name]['is_search'];
        $this->is_print = $_SESSION['xcrud_' . $instanse_name]['is_print'];
    }
    protected function create_bool($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $checked = (int)$value ? ' checked="checked"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="checkbox"' . $checked . ' value="1" name="' . $name . '" class="xcrud-input" data-type="bool" ' . $required .
            $readonly . $disabled . ' />';
    }
    protected function create_int($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $unique = isset($this->unique[$name]) ? ' unique' : '';
        return '<input type="text" value="' . (int)$value . '" name="' . $name . '" class="xcrud-input input-block-level' . $unique .
            '" data-type="int" data-pattern="integer" maxlength="' . $this->field_maxsize[$name] . '" ' . $required . $readonly . $disabled .
            ' />';
    }
    protected function create_float($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $unique = isset($this->unique[$name]) ? ' unique' : '';
        return '<input type="text" value="' . (float)$value . '" name="' . $name . '" class="xcrud-input input-block-level' . $unique .
            '" data-type="float" data-pattern="numeric" maxlength="' . $this->field_maxsize[$name] . '" ' . $required . $readonly .
            $disabled . ' />';
    }
    protected function create_price($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $unique = isset($this->unique[$name]) ? ' unique' : '';
        return '<input type="text" value="' . number_format($value, $this->field_maxsize[$name]['decimals'], '.', $this->
            field_maxsize[$name]['separator']) . '" name="' . $name . '" class="xcrud-input input-block-level' . $unique .
            '" data-type="price" data-pattern="numeric" maxlength="' . $this->field_maxsize[$name]['max'] . '" ' . $required . $readonly .
            $disabled . ' />';
    }
    protected function create_text($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $pattern = isset($this->validation_pattern[$name]) ? ' data-pattern="' . $this->validation_pattern[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $unique = isset($this->unique[$name]) ? ' unique' : '';
        return '<input type="text" value="' . $this->html_safe($value) . '" name="' . $name .
            '" class="xcrud-input input-block-level' . $unique . '" data-type="text" maxlength="' . $this->field_maxsize[$name] .
            '" ' . $required . $pattern . $readonly . $disabled . ' />';
    }
    protected function create_textarea($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $pattern = isset($this->validation_pattern[$name]) ? ' data-pattern="' . $this->validation_pattern[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<textarea name="' . $name . '" rows="8" class="xcrud-input input-block-level" data-type="textarea" ' . $required .
            $pattern . $readonly . $disabled . '>' . $this->html_safe($value) . '</textarea>';
    }
    protected function create_texteditor($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $pattern = isset($this->validation_pattern[$name]) ? ' data-pattern="' . $this->validation_pattern[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<textarea name="' . $name .
            '" rows="5" class="xcrud-input xcrud-texteditor input-block-level" data-type="texteditor" ' . $required . $pattern . $readonly .
            $disabled . '>' . $this->html_safe($value) . '</textarea>';
    }
    protected function create_date($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="text" value="' . $value . '" name="' . $name .
            '" class="xcrud-input xcrud-datepicker" data-type="date" maxlength="10" ' . $required . $readonly . $disabled . ' />';
    }
    protected function create_datetime($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="text" value="' . $value . '" name="' . $name .
            '" class="xcrud-input xcrud-datepicker" data-type="datetime" maxlength="19" ' . $required . $readonly . $disabled .
            ' />';
    }
    protected function create_timestamp($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $value = date('Y-m-d H:i:s', ((preg_replace('/[^0-9]+/', '', $value) == $value) ? $value : strtotime($value)));
        return '<input type="text" value="' . $value . '" name="' . $name .
            '" class="xcrud-input xcrud-datepicker" data-type="timestamp" maxlength="11" ' . $required . $readonly . $disabled .
            ' />';
    }
    protected function create_time($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="text" value="' . $value . '" name="' . $name .
            '" class="xcrud-input xcrud-datepicker" data-type="time" maxlength="8" ' . $required . $readonly . $disabled . ' />';
    }
    protected function create_year($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="text" value="' . $value . '" name="' . $name .
            '" class="xcrud-input xcrud-datepicker" data-type="year" maxlength="4" ' . $required . $readonly . $disabled .
            ' data-pattern="natural" />';
    }
    protected function create_select($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        if (is_array($this->field_maxsize[$name]))
        {
            $out = '<select name="' . $name . '" ' . $required . $disabled . ' class="xcrud-input input-xlarge">';
            foreach ($this->field_maxsize[$name] as $optkey => $opt)
            {
                $selected = ($optkey == $value) ? ' selected="selected"' : '';
                $out .= '<option value="' . $optkey . '"' . $selected . '>' . $this->html_safe($opt) . '</option>';
            }
        } else
        {
            $tmp = explode(',', $this->field_maxsize[$name]);
            $out = '<select name="' . $name . '" ' . $required . $disabled . ' class="xcrud-input input-xlarge">';
            foreach ($tmp as $opt)
            {
                $opt = trim($opt, '\'');
                $selected = ($opt == $value) ? ' selected="selected"' : '';
                $out .= '<option value="' . $this->html_safe($opt) . '"' . $selected . '>' . $this->html_safe($opt) . '</option>';
            }
        }
        $out .= '</select>';
        return $out;
    }
    protected function create_multiselect($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $values = explode(',', $value);
        if (is_array($this->field_maxsize[$name]))
        {
            $size = count($this->field_maxsize[$name]) > 5 ? ' size="5"' : '';
            $out = '<select multiple="multiple" name="' . $name . '"' . $size . ' ' . $required . $disabled .
                ' class="xcrud-input input-xlarge">';
            foreach ($this->field_maxsize[$name] as $optkey => $opt)
            {
                $selected = (in_array($optkey, $values)) ? ' selected="selected"' : '';
                $out .= '<option value="' . $optkey . '"' . $selected . '>' . $opt . '</option>';
            }
        } else
        {
            $tmp = explode(',', $this->field_maxsize[$name]);
            $size = count($tmp) > 5 ? ' size="5"' : '';
            $out = '<select multiple="multiple" name="' . $name . '"' . $size . ' ' . $required . $disabled .
                ' class="xcrud-input input-xlarge">';
            foreach ($tmp as $opt)
            {
                $opt = trim($opt, '\'');
                $selected = (in_array($opt, $values)) ? ' selected="selected"' : '';
                $out .= '<option value="' . $this->html_safe($opt) . '"' . $selected . '>' . $this->html_safe($opt) . '</option>';
            }
        }

        $out .= '</select>';
        return $out;
    }
    protected function create_hidden($name, $value = '')
    {
        return '<input type="hidden" value="' . $this->html_safe($value) . '" name="' . $name . '" class="xcrud-input" />';
    }
    protected function create_password($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $pattern = isset($this->validation_pattern[$name]) ? ' data-pattern="' . $this->validation_pattern[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? ' readonly="readonly"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        return '<input type="password" value="" name="' . $name . '" class="xcrud-input" data-type="text" maxlength="' . $this->
            field_maxsize[$name] . '" ' . $required . $pattern . $readonly . $disabled . ' />';
    }
    protected function create_relation($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $disabled = isset($this->disabled[$name]) ? ' disabled="disabled"' : '';
        $db = Xcrud_db::get_instance($this->connection);
        $where_arr = array();
        if ($this->join[$name]['multi'])
        {
            $multi = ' multiple="multiple" size="5"';
            $values = explode(',', $value);
        } else
        {
            $multi = '';
            $values = array($value);
        }
        if ($this->join[$name]['rel_where'])
        {
            if (is_array($this->join[$name]['rel_where']))
            {
                foreach ($this->join[$name]['rel_where'] as $field => $val)
                {
                    $where_arr[] = ($val ? (isset($this->no_quotes[$field]) ? $this->_prepare_field($field) . $db->escape($val, true) : $this->
                        _prepare_field($field) . $db->escape($val)) : $field);
                }
            } else
                $where_arr[] = $this->join[$name]['rel_where'];
        }
        if ($where_arr)
            $where = 'WHERE ' . implode(' AND ', $where_arr);
        else
            $where = '';
        //$db->query("SELECT `{$this->join[$name]['rel_field']}` AS `field`,`{$this->join[$name]['rel_name']}` AS name FROM `{$this->join[$name]['rel_tbl']}` {$where} ORDER BY `{$this->join[$name]['rel_name']}` ASC");
        $db->query("SELECT `{$this->join[$name]['rel_field']}` AS `field`," . (is_array($this->join[$name]['rel_name']) ?
            "CONCAT_WS('{$this->join[$name]['rel_separator']}',`" . implode('`,`', $this->join[$name]['rel_name']) . "`)" : "`{$this->join[$name]['rel_name']}`") .
            " AS `name` FROM `{$this->join[$name]['rel_tbl']}` {$where} ORDER BY `name` ASC");
        $options = $db->result();
        $out = '<select name="' . $name . '" ' . $required . $disabled . $multi . ' class="xcrud-input input-xlarge">';
        $out .= '<option value=""> - none - </option>';
        foreach ($options as $opt)
        {
            $selected = (in_array($opt->field, $values)) ? ' selected="selected"' : '';
            $out .= '<option value="' . $this->html_safe($opt->field) . '"' . $selected . '>' . $this->html_safe($opt->name) .
                '</option>';
        }
        $out .= '</select>';
        unset($options);
        return $out;
    }
    protected function create_file($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? true : false;
        $disabled = isset($this->disabled[$name]) ? true : false;
        $ext = trim(strtolower(strrchr($value, '.')), '.');
        $folder = rtrim(isset($this->upload_folder[$name]) ? $this->upload_folder[$name] : $this->upload_folder_def, '/');
        $file_full_path = realpath($folder) . '/' . $value;
        return '<div class="xcrud-file-container">
            <input type="hidden" name="' . $name . '" value="' . $value . '" class="xcrud-input" data-type="file" ' . $required .
            ' />
            ' . ($value ? '<a target="_blank" href="' . $this->file_link($name, $value) . '" class="xcrud-file xcrud-' .
            trim($ext, '.') . '">' . $value . '</a>' . $this->_file_size($file_full_path) .
            '<a href="javascript:void(0);" class="xcrud-remove-file xcrud-action-button btn btn-danger" data-type="file" data-file="' .
            $value . '" data-field="' . $name . '">remove</a>' : '<span class="xcrud-nofile">no file</span>') . '
        </div>
        ' . (($readonly or $disabled) ? '' :
            '<span class="xcrud-add-file xcrud-action-button btn btn-success"><i class="icon-upload icon-white"></i> Add file<input type="file" name="attach" id="' .
            $name . '-file" data-field="' . $name . '" data-type="file" class="xcrud-upload" value="" /></span>');
    }
    protected function create_image($name, $value = '')
    {
        $required = isset($this->validation_required[$name]) ? ' data-required="' . $this->validation_required[$name] . '"' : '';
        $readonly = isset($this->readonly[$name]) ? true : false;
        $disabled = isset($this->disabled[$name]) ? true : false;
        //$ext = trim(strtolower(strrchr($value, '.')), '.');
        return '<div class="xcrud-file-container">
            ' . ((isset($this->upload_config[$name]['blob']) && $this->upload_config[$name]['blob'] === true) ?
            '<input type="hidden" name="' . $name . '" value="' . ($value ? 'blob-storage' : '') .
            '" class="xcrud-input" data-type="file" ' . $required . ' />' : '<input type="hidden" name="' . $name . '" value="' . $value .
            '" class="xcrud-input" data-type="file" ' . $required . ' />') . ($value ?
            '<img class="xcrud-image img-polaroid" alt="" src="' . $this->file_link($name, ((isset($this->upload_config[$name]['blob']) &&
            $this->upload_config[$name]['blob'] === true) ? 'image.jpg' : $value)) . '" />
            <a href="javascript:void(0);" class="xcrud-remove-file xcrud-action-button btn btn-danger" data-type="file" data-file="' .
            ((isset($this->upload_config[$name]['blob']) && $this->upload_config[$name]['blob'] === true) ? 'blob-storage' : $value) .
            '" data-field="' . $name . '">remove</a>' : '<span class="xcrud-noimage">no file</span>') . '
        </div>
        ' . (($readonly or $disabled) ? '' :
            '<span class="xcrud-add-file xcrud-action-button btn btn-success"><i class="icon-upload icon-white"></i> Add image<input type="file" name="attach" id="' .
            $name . '-file" data-field="' . $name .
            '" data-type="image" accept="image/jpeg,image/png,image/gif" class="xcrud-upload" value="" /></span>');
    }
    protected function create_binary($name, $value = '')
    {
        return $value ? '[binary data]' : '[binary null]';
    }
    protected function create_fk_relations($list)
    {
        if ($this->fk_join)
        {
            $db = Xcrud_db::get_instance($this->connection);
            foreach ($this->fk_join as $fk)
            {
                $fval = $list[$fk['field']];
                $where_arr = array();
                if ($fk['rel_where'])
                {
                    if (is_array($params['rel_where']))
                    {
                        foreach ($params['rel_where'] as $field => $val)
                        {
                            if ($val or is_int($val) or is_float($val))
                            {
                                $where_arr[] = "`a`." . $this->_prepare_field($field) . (isset($this->no_quotes[$field]) ? $db->escape($val, true) : $db->
                                    escape($val));
                            } else
                            {
                                $where_arr[] = $field;
                            }
                        }
                    } else
                        $where_arr[] = $params['rel_where'];
                }
                $db->query("SELECT `a`.`{$fk['rel_field']}`, `a`.`{$fk['rel_name']}`, IF(`b`.`{$fk['in_fk_field']}` = '{$fval}', 1, 0) AS `selected` 
                    FROM `{$fk['rel_table']}` AS `a` LEFT JOIN `{$fk['fk_table']}` AS `b` ON `a`.`{$fk['rel_field']}` = `b`.`{$fk['out_fk_field']}` 
                    WHERE `{$fk['in_fk_field']}` = '{$fval}' " . ($where_arr ? 'AND ' . implode(' AND ', $where_arr) :
                    ''))->result();
            }
        }
    }
    protected function benchmark_start()
    {
        if ($this->benchmark)
        {
            $this->time_start = (float)str_replace(' ', '.', microtime());
            $this->memory_start = memory_get_usage();
        }
    }
    protected function benchmark_end()
    {
        if ($this->benchmark)
        {
            $this->time_end = (float)str_replace(' ', '.', microtime());
            $this->memory_end = memory_get_usage();
            $out = 'Execution time: ' . (number_format($this->time_end - $this->time_start, 3, '.', '')) . ' s';
            $out .= '<br />Memory usage: ' . (number_format(($this->memory_end - $this->memory_start) / 1024 / 1024, 2, '.', '')) .
                ' MB';
            return $out;
        }
    }
    protected function error($text = 'Error!')
    {
        exit('<div class="xcrud-error" style="padding:15px;color:#EE9401;margin:10px;border:1px solid#EE9401;border-radius:2px;">' .
            $text . '</div>');
    }
    protected function _upload()
    {
        switch ($this->_post('type'))
        {
            case 'image':
                return $this->_upload_image();
                break;
            case 'file':
                return $this->_upload_file();
                break;
            default:
                return $this->error();
                break;
        }
    }
    protected function _upload_file()
    {
        $field = $this->_post('field');
        $oldfile = $this->_post('oldfile') or 0;
        if (isset($_FILES) && isset($_FILES['attach']) && !$_FILES['attach']['error'])
        {
            $file = $_FILES['attach'];
            $ext = strtolower(strrchr($file['name'], '.'));
            if (isset($this->upload_config[$field]['not_rename']) && $this->upload_config[$field]['not_rename'] === true)
                $file_name = $this->_clean_file_name($file['name']);
            else
                $file_name = sha1(microtime()) . $ext;
            $folder = rtrim(isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def, '/');
            $file_full_path = realpath($folder) . '/' . $file_name;
            if ($oldfile != $file_name)
                $this->upload_to_remove[$oldfile] = $field;
            $this->upload_to_save[$file_name] = $field;
            $this->_export_special();
            move_uploaded_file($file['tmp_name'], $file_full_path);
            $required = isset($this->validation_required[$field]) ? ' data-required="' . $this->validation_required[$name] . '"' :
                '';
            echo '<a target="_blank" href="' . $this->file_link($field, $file_name) . '" class="xcrud-file xcrud-' . trim($ext, '.') .
                '">' . $file_name . '</a>';
            echo $this->_file_size($file_full_path);
            echo '<a href="javascript:void(0);" class="xcrud-remove-file xcrud-action-button btn btn-danger" data-type="file" data-file="' .
                $file_name . '" data-field="' . $field . '">remove</a>';
            echo '<input type="hidden" name="' . $field . '" value="' . $file_name . '" class="xcrud-input" data-type="image" ' . $required .
                ' />';
            echo '<input type="hidden" name="new_key" value="' . $this->key . '" class="new_key" />';
        } else
            return $this->error('File is not uploaded');
    }
    protected function _upload_image()
    {
        $field = $this->_post('field');
        $oldfile = $this->_post('oldfile') or 0;
        if (isset($_FILES) && isset($_FILES['attach']) && !$_FILES['attach']['error'])
        {
            $file = $_FILES['attach'];
            $ext = strtolower(strrchr($file['name'], '.'));
            $file_name = sha1(microtime()) . $ext;
            $folder = rtrim(isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def, '/');
            $file_full_path = realpath($folder) . '/' . $file_name;
            $this->upload_to_remove[$oldfile] = $field;
            $this->upload_to_save[$file_name] = $field;
            $this->_export_special();
            move_uploaded_file($file['tmp_name'], $file_full_path);
            $this->_try_change_size($field, $file_full_path);
            $this->_try_create_thumb($field, $file_full_path);
            $required = isset($this->validation_required[$field]) ? ' data-required="' . $this->validation_required[$field] . '"' :
                '';
            echo '<img class="xcrud-image img-polaroid" alt="" src="' . $this->file_link($field, ((isset($this->upload_config[$field]['blob']) &&
                $this->upload_config[$field]['blob'] === true) ? 'image.jpg' : $file_name)) . '" />';
            echo '<input type="hidden" name="' . $field . '" value="' . $file_name . '" class="xcrud-input" data-type="image" ' . $required .
                ' />';
            echo '<input type="hidden" name="new_key" value="' . $this->key . '" class="new_key" />';
            echo '<a href="javascript:void(0);" class="xcrud-remove-file xcrud-action-button btn btn-danger" data-type="image" data-file="' .
                $file_name . '" data-field="' . $field . '">remove</a>';
        } else
            return $this->error('File is not uploaded');
    }
    protected function _try_change_size($field, $imgpath)
    {
        $crop = (isset($this->upload_config[$field]['crop']) && $this->upload_config[$field]['crop']) ? true : false;
        $width = (isset($this->upload_config[$field]['width']) && $this->upload_config[$field]['width']) ? $this->upload_config[$field]['width'] : false;
        $height = (isset($this->upload_config[$field]['height']) && $this->upload_config[$field]['height']) ? $this->
            upload_config[$field]['height'] : false;
        if ($crop && $width && $height)
        {
            $this->_image_crop($imgpath, $imgpath, $width, $height);
        } else
            if ($width or $height)
            {
                $this->_image_resize($imgpath, $imgpath, $width, $height);
            }
    }
    protected function _try_create_thumb($field, $imgpath)
    {
        $crop = (isset($this->upload_config[$field]['thumb_crop']) && $this->upload_config[$field]['thumb_crop']) ? true : false;
        $width = (isset($this->upload_config[$field]['thumb_width']) && $this->upload_config[$field]['thumb_width']) ? $this->
            upload_config[$field]['thumb_width'] : false;
        $height = (isset($this->upload_config[$field]['thumb_height']) && $this->upload_config[$field]['thumb_height']) ? $this->
            upload_config[$field]['thumb_height'] : false;
        $marker = (isset($this->upload_config[$field]['thumb_marker']) && $this->upload_config[$field]['thumb_marker']) ? $this->
            upload_config[$field]['thumb_marker'] : '_thumb';
        $thumb_path = substr_replace($imgpath, $marker, mb_strrpos($imgpath, '.'), 0);
        if ($crop && $width && $height)
        {
            $this->_image_crop($imgpath, $thumb_path, $width, $height);
        } else
            if ($width or $height)
            {
                $this->_image_resize($imgpath, $thumb_path, $width, $height);
            }
    }
    protected function _remove_upload()
    {
        switch ($this->_post('type'))
        {
            case 'image':
                return $this->_remove_image();
                break;
            case 'file':
                return $this->_remove_file();
                break;
            default:
                return $this->error();
                break;
        }
    }
    protected function _remove_file()
    {
        $field = $this->_post('field');
        $file = $this->_post('file');
        $this->upload_to_remove[$file] = $field;
        $this->_export_special();
        $required = isset($this->validation_required[$field]) ? ' data-required="' . $this->validation_required[$field] . '"' :
            '';
        echo '<input type="hidden" name="' . $field . '" value="" class="xcrud-input" data-type="file" ' . $required . ' />';
        echo '<input type="hidden" name="new_key" value="' . $this->key . '" class="new_key" />
            <span class="xcrud-nofile">no file</span>';
    }
    protected function _remove_image()
    {
        $field = $this->_post('field');
        $file = $this->_post('file');
        $required = isset($this->validation_required[$field]) ? ' data-required="' . $this->validation_required[$field] . '"' :
            '';
        $this->upload_to_remove[$file] = $field;
        $this->_export_special();
        echo '<input type="hidden" name="' . $field . '" value="" class="xcrud-input" data-type="image" ' . $required . ' />';
        echo '<input type="hidden" name="new_key" value="' . $this->key . '" class="new_key" />
            <span class="xcrud-noimage">no image</span>';
    }
    protected function _remove_and_save_uploads()
    {
        switch ($this->_post('task'))
        {
            case 'save':
                if ($this->upload_to_remove)
                {
                    foreach ($this->upload_to_remove as $file => $field)
                    {
                        if ($file != 0)
                        {
                            $folder = rtrim(isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def, '/');
                            $file_full_path = realpath($folder) . '/' . $file;
                            @unlink($file_full_path);
                            $marker = (isset($this->upload_config[$field]['thumb_marker']) && $this->upload_config[$field]['thumb_marker']) ? $this->
                                upload_config[$field]['thumb_marker'] : '_thumb';
                            $thumb_path = substr_replace($file_full_path, $marker, mb_strrpos($file_full_path, '.'), 0);
                            @unlink($thumb_path);
                        }
                    }
                    $this->upload_to_save = array();
                    $this->upload_to_remove = array();
                }
                break;
            case 'list':
            case '':
                if ($this->upload_to_save)
                {
                    foreach ($this->upload_to_save as $file => $field)
                    {
                        $folder = rtrim(isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def, '/');
                        $file_full_path = realpath($folder) . '/' . $file;
                        @unlink($file_full_path);
                        $marker = (isset($this->upload_config[$field]['thumb_marker']) && $this->upload_config[$field]['thumb_marker']) ? $this->
                            upload_config[$field]['thumb_marker'] : '_thumb';
                        $thumb_path = substr_replace($file_full_path, $marker, mb_strrpos($file_full_path, '.'), 0);
                        @unlink($thumb_path);
                    }
                    $f_bak = array();
                    foreach ($this->upload_to_remove as $file => $field)
                    {
                        if (!isset($f_bak[$field]))
                        {
                            $f_bak[$field] = true;
                            continue;
                        }
                        $folder = rtrim(isset($this->upload_folder[$field]) ? $this->upload_folder[$field] : $this->upload_folder_def, '/');
                        $file_full_path = realpath($folder) . '/' . $file;
                        @unlink($file_full_path);
                        $marker = (isset($this->upload_config[$field]['thumb_marker']) && $this->upload_config[$field]['thumb_marker']) ? $this->
                            upload_config[$field]['thumb_marker'] : '_thumb';
                        $thumb_path = substr_replace($file_full_path, $marker, mb_strrpos($file_full_path, '.'), 0);
                        @unlink($thumb_path);
                    }
                    $this->upload_to_save = array();
                    $this->upload_to_remove = array();
                }
                break;
        }
    }
    protected function _image_resize($src_file, $dest_file, $new_size_w = false, $new_size_h = false, $dest_qual = 92)
    {
        list($srcWidth, $srcHeight, $type) = getimagesize($src_file);
        switch ($type)
        {
            case 1:
                $src_img = imagecreatefromgif($src_file);
                break;
            case 2:
                $src_img = imagecreatefromjpeg($src_file);
                break;
            case 3:
                $src_img = imagecreatefrompng($src_file);
                break;
            default:
                $this->error('File Type Not Supported!');
                return false;
        }
        if ($srcWidth >= $srcHeight)
        {
            $ratio = (($new_size_w ? $srcWidth : $srcHeight) / ($new_size_w ? $new_size_w : $new_size_h));
            $ratio = max($ratio, 1.0);
            $destWidth = ($srcWidth / $ratio);
            $destHeight = ($srcHeight / $ratio);
            if ($destHeight > ($new_size_h ? $new_size_h : $new_size_w))
            {
                $ratio = ($destHeight / ($new_size_h ? $new_size_h : $new_size_w));
                $ratio = max($ratio, 1.0);
                $destWidth = ($destWidth / $ratio);
                $destHeight = ($destHeight / $ratio);
            }
        } elseif ($srcHeight > $srcWidth)
        {
            $ratio = (($new_size_h ? $srcHeight : $srcWidth) / ($new_size_h ? $new_size_h : $new_size_w));
            $ratio = max($ratio, 1.0);
            $destWidth = ($srcWidth / $ratio);
            $destHeight = ($srcHeight / $ratio);
            if ($destWidth > ($new_size_w ? $new_size_w : $new_size_h))
            {
                $ratio = ($destWidth / ($new_size_w ? $new_size_w : $new_size_h));
                $ratio = max($ratio, 1.0);
                $destWidth = ($destWidth / $ratio);
                $destHeight = ($destHeight / $ratio);
            }
        }
        $dst_img = imagecreatetruecolor($destWidth, $destHeight);
        imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
        imagedestroy($src_img);
        switch ($type)
        {
            case 1:
                imagegif($dst_img, $dest_file);
                break;
            case 2:
                imagejpeg($dst_img, $dest_file, $dest_qual);
                break;
            case 3:
                imagepng($dst_img, $dest_file);
                break;
            default:
                $this->error('File Type Not Supported! ');
                return false;
        }
        imagedestroy($dst_img);
        $newimgarray = array($destWidth, $destHeight);
        return $newimgarray;
    }
    protected function _image_crop($srcFile, $dstFile, $ad_thumbwidth, $ad_thumbheight, $ad_thumbquality = 92)
    {
        list($srcWidth, $srcHeight, $type) = getimagesize($srcFile);
        switch ($type)
        {
            case 1:
                $srcHandle = imagecreatefromgif($srcFile);
                break;
            case 2:
                $srcHandle = imagecreatefromjpeg($srcFile);
                break;
            case 3:
                $srcHandle = imagecreatefrompng($srcFile);
                break;
            default:
                $this->error('File Type Not Supported!');
                return false;
        }
        if (!$srcHandle)
        {
            $this->error('Could not execute imagecreatefrom() function! ');
            return false;
        }
        if ($srcHeight < $srcWidth)
        {
            $ratio = (double)($srcHeight / $ad_thumbheight);
            $cpyWidth = round($ad_thumbwidth * $ratio);
            if ($cpyWidth > $srcWidth)
            {
                $ratio = (double)($srcWidth / $ad_thumbwidth);
                $cpyWidth = $srcWidth;
                $cpyHeight = round($ad_thumbheight * $ratio);
                $xOffset = 0;
                $yOffset = round(($srcHeight - $cpyHeight) / 2);
            } else
            {
                $cpyHeight = $srcHeight;
                $xOffset = round(($srcWidth - $cpyWidth) / 2);
                $yOffset = 0;
            }
        } else
        {
            $ratio = (double)($srcWidth / $ad_thumbwidth);
            $cpyHeight = round($ad_thumbheight * $ratio);
            if ($cpyHeight > $srcHeight)
            {
                $ratio = (double)($srcHeight / $ad_thumbheight);
                $cpyHeight = $srcHeight;
                $cpyWidth = round($ad_thumbwidth * $ratio);
                $xOffset = round(($srcWidth - $cpyWidth) / 2);
                $yOffset = 0;
            } else
            {
                $cpyWidth = $srcWidth;
                $xOffset = 0;
                $yOffset = round(($srcHeight - $cpyHeight) / 2);
            }
        }
        $dstHandle = ImageCreateTrueColor($ad_thumbwidth, $ad_thumbheight);
        if (!imagecopyresampled($dstHandle, $srcHandle, 0, 0, $xOffset, $yOffset, $ad_thumbwidth, $ad_thumbheight, $cpyWidth, $cpyHeight))
        {
            $this->error('Could not execute imagecopyresampled() function! ');
            return false;
        }
        imagedestroy($srcHandle);
        switch ($type)
        {
            case 1:
                imagegif($dstHandle, $dstFile);
                break;
            case 2:
                imagejpeg($dstHandle, $dstFile, $ad_thumbquality);
                break;
            case 3:
                imagepng($dstHandle, $dstFile);
                break;
            default:
                $this->error('File Type Not Supported! ');
                return false;
        }
        imagedestroy($dstHandle);
        return true;
    }
    protected function _sort_defaults()
    {
        $new_defaults = array();
        foreach ($this->fields as $field)
        {
            $new_defaults[$field] = $this->defaults[$field];
        }
        $this->defaults = $new_defaults;
    }
    protected function _clean_file_name($txt)
    {
        $replace = array(
            'Š' => 'S',
            'Œ' => 'O',
            'Ž' => 'Z',
            'š' => 's',
            'œ' => 'oe',
            'ž' => 'z',
            'Ÿ' => 'Y',
            '¥' => 'Y',
            'µ' => 'u',
            'À' => 'A',
            'Á' => 'A',
            'Â' => 'A',
            'Ã' => 'A',
            'Ä' => 'A',
            'Å' => 'A',
            'Æ' => 'A',
            'Ç' => 'C',
            'È' => 'E',
            'É' => 'E',
            'Ê' => 'E',
            'Ë' => 'E',
            'Ì' => 'I',
            'Í' => 'I',
            'Î' => 'I',
            'Ï' => 'I',
            'Ð' => 'D',
            'Ñ' => 'N',
            'Ò' => 'O',
            'Ó' => 'O',
            'Ô' => 'O',
            'Õ' => 'O',
            'Ö' => 'O',
            'Ø' => 'O',
            'Ù' => 'U',
            'Ú' => 'U',
            'Û' => 'U',
            'Ü' => 'U',
            'Ý' => 'Y',
            'ß' => 'ss',
            'à' => 'a',
            'á' => 'a',
            'â' => 'a',
            'ã' => 'a',
            'ä' => 'a',
            'å' => 'a',
            'æ' => 'a',
            'ç' => 'c',
            'è' => 'e',
            'é' => 'e',
            'ê' => 'e',
            'ë' => 'e',
            'ì' => 'i',
            'í' => 'i',
            'î' => 'i',
            'ï' => 'i',
            'ð' => 'o',
            'ñ' => 'n',
            'ò' => 'o',
            'ó' => 'o',
            'ô' => 'o',
            'õ' => 'o',
            'ö' => 'o',
            'ø' => 'o',
            'ù' => 'u',
            'ú' => 'u',
            'û' => 'u',
            'ü' => 'u',
            'ý' => 'y',
            'ÿ' => 'y',
            'ă' => 'a',
            'ş' => 's',
            'ţ' => 't',
            'ț' => 't',
            'Ț' => 'T',
            'Ș' => 'S',
            'ș' => 's',
            'Ş' => 'S',
            'А' => 'A',
            'Б' => 'B',
            'В' => 'V',
            'Г' => 'G',
            'Д' => 'D',
            'Е' => 'E',
            'Ё' => 'E',
            'Ж' => 'J',
            'З' => 'Z',
            'И' => 'I',
            'Й' => 'I',
            'К' => 'K',
            'Л' => 'L',
            'М' => 'M',
            'Н' => 'N',
            'О' => 'O',
            'П' => 'P',
            'Р' => 'R',
            'С' => 'S',
            'Т' => 'T',
            'У' => 'U',
            'Ф' => 'F',
            'Х' => 'H',
            'Ц' => 'C',
            'Ч' => 'CH',
            'Ш' => 'SH',
            'Щ' => 'SH',
            'Ы' => 'Y',
            'Э' => 'E',
            'Ю' => 'YU',
            'Я' => 'YA',
            'а' => 'a',
            'б' => 'b',
            'в' => 'v',
            'г' => 'g',
            'д' => 'd',
            'е' => 'e',
            'ё' => 'e',
            'ж' => 'j',
            'з' => 'z',
            'и' => 'i',
            'й' => 'i',
            'к' => 'k',
            'л' => 'l',
            'м' => 'm',
            'н' => 'n',
            'о' => 'o',
            'п' => 'p',
            'р' => 'r',
            'с' => 's',
            'т' => 't',
            'у' => 'u',
            'ф' => 'f',
            'х' => 'H',
            'ц' => 'c',
            'ч' => 'ch',
            'ш' => 'sh',
            'щ' => 'sh',
            'ы' => 'y',
            'э' => 'e',
            'ю' => 'yu',
            'я' => 'ya',
            'Ā' => 'A',
            'ā' => 'a',
            'Č' => 'C',
            'č' => 'c',
            'Ē' => 'E',
            'ē' => 'e',
            'Ģ' => 'G',
            'ģ' => 'g',
            'Ī' => 'I',
            'ī' => 'i',
            'Ķ' => 'K',
            'ķ' => 'k',
            'Ļ' => 'L',
            'ļ' => 'l',
            'Ņ' => 'N',
            'ņ' => 'n',
            'Ū' => 'U',
            'ū' => 'u',
            ' ' => '_');
        $txt = str_replace(array_keys($replace), array_values($replace), $txt);
        $txt = preg_replace('/[^a-zA-Z0-9_\-\.]+/', '', $txt);
        return $txt;
    }
    protected function _file_size($path)
    {
        return number_format(filesize($path) / 1024, 2, '.', ' ') . ' KB';
    }
    protected function _prepare_field($field)
    {
        preg_match_all('/([^<>!=]+)/', $field, $matches);
        preg_match_all('/([<>!=]+)/', $field, $matches2);
        return '`' . trim($matches[0][0]) . '`' . ($matches2[0] ? implode('', $matches2[0]) : '=');
    }
    protected function _compare($val1, $operator, $val2)
    {
        switch ($operator)
        {
            case '=':
                return ($val1 == $val2) ? true : false;
            case '>':
                return ($val1 > $val2) ? true : false;
            case '<':
                return ($val1 < $val2) ? true : false;
            case '>=':
                return ($val1 >= $val2) ? true : false;
            case '<=':
                return ($val1 <= $val2) ? true : false;
            case '!=':
                return ($val1 != $val2) ? true : false;
            case '^=':
                return (mb_strpos($val1, $val2, 0, Xcrud_config::$mbencoding) === 0) ? true : false;
            case '$=':
                return (mb_strpos($val1, $val2, 0, Xcrud_config::$mbencoding) == (mb_strlen($val1, Xcrud_config::$mbencoding) -
                    mb_strlen($val2, Xcrud_config::$mbencoding))) ? true : false;
            case '~=':
                return (mb_strpos($val1, $val2, 0, Xcrud_config::$mbencoding) !== false) ? true : false;
            default:
                return false;
        }
    }
    protected function _render_list_item($field, $value, $primary_key)
    {
        if (isset($this->field_type[$field]))
        {
            if ($this->field_type[$field] == 'select' && is_array($this->field_maxsize[$field]))
                return $this->field_maxsize[$field][$value];
            if ($this->field_type[$field] == 'timestamp')
                return date('Y-m-d H:i:s', ((preg_replace('/[^0-9]+/', '', $value) == $value) ? $value : strtotime($value)));
            if ($this->field_type[$field] == 'bool')
                return ($value) ? 'Yes' : 'No';
            if ($this->field_type[$field] == 'price')
                return $this->field_maxsize[$field]['prefix'] . number_format($value, $this->field_maxsize[$field]['decimals'], '.', $this->
                    field_maxsize[$field]['separator'] . $this->field_maxsize[$field]['suffix']);
            if (Xcrud_config::$images_in_grid && $this->field_type[$field] == 'image' && $value)
            {
                return '<img class="xcrud-image" style="max-height: ' . Xcrud_config::$images_in_grid_height . 'px;" alt="" src="' . $this->
                    file_link($field, ((isset($this->upload_config[$field]['blob']) && $this->upload_config[$field]['blob'] === true) ?
                    'image.jpg' : $value), $primary_key, ((isset($this->upload_config[$field]['thumb_width'])) or isset($this->
                    upload_config[$field]['thumb_width'])) ? true : false) . '" />';
            }
            if (($this->field_type[$field] == 'file' or $this->field_type[$field] == 'image') && $value)
            {
                $ext = trim(strtolower(strrchr($value, '.')), '.');
                return '<a target="_blank" href="' . $this->file_link($field, $value, $primary_key) . '" class="xcrud-file xcrud-' .
                    trim($ext, '.') . '">' . (isset($this->upload_config[$field]['text']) ? $this->upload_config[$field]['text'] : $value) .
                    '</a>';
            }
            if (Xcrud_config::$clickable_list_links && $this->field_type[$field] == 'text')
            {
                if (mb_strpos($value, 'http', 0, Xcrud_config::$mbencoding) !== false)
                    return '<a target="_blank" href="' . $value . '">' . ($this->links_label ? $this->links_label['text'] : $this->_cut($value,
                        $this->column_cut)) . '</a>';
                elseif (mb_strpos($value, '@', 0, Xcrud_config::$mbencoding) !== false)
                    return '<a target="_blank" href="mailto:' . $value . '">' . ($this->emails_label ? $this->emails_label['text'] : $this->
                        _cut($value, $this->column_cut)) . '</a>';
            }
            if (isset($this->binary[$field]))
            {
                return ($value) ? '[binary data]' : '';
            }
            return $this->_cut($value, $this->column_cut);
        }
        // return $this->_cut($value, $this->column_cut);
    }
    protected function _render_list_buttons(&$row)
    {
        $out = '';
        $is_bootstrap = $this->theme = 'bootstrap' ? true : false;
        if ($this->buttons)
        {
            foreach ($this->buttons as $button)
            {
                $href = array();
                if ($button['params'])
                {
                    foreach ($button['params'] as $key => $value)
                    {
                        $href[] = rawurlencode($key) . '=' . rawurlencode($row->$value);
                    }
                }
                $out .= '<a class="xcrud-button-link ' . (($is_bootstrap && !$button['class']) ? 'btn-small btn-primary ' : '') . $button['class'] .
                    '" title="' . $this->html_safe($button['name']) . '" href="' . $button['link'] . ($href ? ((mb_strpos($button['link'],
                    '?', 0, Xcrud_config::$mbencoding) === false) ? '?' : '&amp;') . implode('&amp;', $href) : '') . '"><i class="' . ($button['icon'] ?
                    $button['icon'] : 'icon-globe') . '"></i></a> ';
            }
        }
        $out .= $this->is_duplicate ? '<a class="xcrud-clone' . ($is_bootstrap ? ' btn-inverse btn-small' : '') .
            '" data-primary="' . ($row->primary_key) .
            '" title="Duplicate" href="javascript:void(0);"><i class="icon-plus icon-white"></i></a>' : '';
        $out .= $this->is_edit ? ' <a class="xcrud-edit' . ($is_bootstrap ? ' btn-warning btn-small' : '') . '" data-primary="' . ($row->
            primary_key) . '" title="Edit" href="javascript:void(0);"><i class="icon-edit icon-white"></i></a>' : '';
        $out .= $this->is_remove ? ' <a class="xcrud-remove' . ($is_bootstrap ? ' btn-danger btn-small' : '') . ($this->
            remove_confirm ? ' xcrud-confirm' : '') . '" data-primary="' . ($row->primary_key) .
            '" title="Remove" href="javascript:void(0);"><i class="icon-remove icon-white"></i></a>' : '';
        return $out;
    }

    protected function _check_unique_value()
    {
        $field = $this->_post('field');
        $value = $this->_post('value');
        $primary = $this->_post('primary');
        if (!$this->primary)
            $this->_set_columns($this->_table_info());
        $db = Xcrud_db::get_instance($this->connection);
        $db->query("SELECT COUNT(*) AS `count` FROM `{$this->table}` WHERE `{$field}`='{$value}' AND `{$this->primary}`!='{$primary}' LIMIT 1");
        $list = $db->row();
        $data = array();
        $data['unique'] = ($list->count > 0) ? 0 : 1;
        $data['key'] = $this->key;
        $this->_export_special();
        echo json_encode($data);
    }
    protected function _check_url($url)
    {
        $host = trim($_SERVER['HTTP_HOST'], '/');
        $scheme = isset($_SERVER['HTTPS']) ? 'https://' : 'http://';
        $sh_pos = mb_strpos($url, '://', 0, Xcrud_config::$mbencoding);
        $url = ($sh_pos === false) ? $url : mb_substr($url, $sh_pos + 3);
        $eh_pos = mb_strpos($url, '/', 0, Xcrud_config::$mbencoding);
        $u_host = ($eh_pos === false) ? false : trim(mb_substr($url, 0, $eh_pos, Xcrud_config::$mbencoding), '/');
        if (!$u_host)
            return rtrim($url, '/');
        if (ltrim($host, 'w.') == ltrim($u_host, 'w.'))
            return $scheme . $host . rtrim(mb_substr($url, $eh_pos), '/');
        else
            return $scheme . rtrim($url, '/');
    }
    protected function file_link($field, $val = 'image.jpg', $primary_key = false, $thumb = false)
    {
        return $this->crud_url . '/xcrud_image.php/?instance=' . $this->instance_name() . '&amp;field=' . $field . '&amp;key=' .
            $this->key . (Xcrud_config::$dynamic_session ? '&amp;sess_name=' . $this->sess_name : '') . ($primary_key ?
            '&amp;primary_key=' . $primary_key : '') . ($thumb ? '&amp;thumb=true' : '');
    }
    protected function html_safe($text)
    {
        return htmlspecialchars($text, ENT_QUOTES, Xcrud_config::$mbencoding);
    }
    protected function _clone_row($primary)
    {
        if (!$this->primary_ai)
            $this->error('Duplication impossible. Table does not have a primary autoincrement field.');
        if (count($this->unique_ind) > 0)
            $this->error('Duplication impossible. The table has a unique field.');

        $ins_field_list = $sel_field_list = ('`' . implode('`,`', $this->clone_fields) . '`');
        $db = Xcrud_db::get_instance($this->connection);
        if ($this->pass_var_create)
        {
            foreach ($this->pass_var_create as $field => $value)
            {
                $sel_field_list = str_replace('`' . $field . '`', $db->escape($value), $sel_field_list);
            }
        }
        $db->query("INSERT INTO `{$this->table}` ({$ins_field_list}) SELECT {$sel_field_list} FROM `{$this->table}` WHERE `{$this->primary}`='{$primary}' LIMIT 1");
    }
    protected function send_email($to, $subject = '(No subject)', $message = '', $cc = array(), $html = true)
    {
        $header = 'MIME-Version: 1.0' . "\r\n" . 'Content-type: text/' . ($html ? 'html' : 'plain') . '; charset=UTF-8' . "\r\n" .
            'From: ' . Xcrud_config::$email_from_name . ' <' . Xcrud_config::$email_from . ">\r\n";
        if ($cc)
            $header .= 'Cc: ' . implode(',', $cc) . "\r\n";
        if ($html)
            $message = '<!DOCTYPE HTML><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>' . $subject .
                '</title></head><body>' . $message . '</body></html>';
        mail($to, '=?UTF-8?B?' . base64_encode($subject) . '?=', $message, $header);
    }

}
